node

一、nodejs特点

单线程:

好处:减少了内存的开销,操作系统的内存换页

坏处:一个用户造成了线程的奔溃,整个服务都奔溃了

非阻塞I/O:一个线程永远在执行计算操作,这个线程的CPU核心利用率是100%

事件驱动:底层的代码中,近半数都用于事件队列,回调函数的队列中

 

二、安装

1、https://nodejs.org/en/下载安装

2、配置环境变量

3、查看版本号:node -v

4、运行:node 文件名

 

三、基本语法

访问任何一个文件都需要静态出来 ,文件名字和和访问路径的名字没有任何关系

var http = require("http");===>require表示引包,引包就是引用自己的一个特殊功能

var fs=require("fs")===>读取目录文件

 

var server = http.createServer(function(req,res){===>createServer:创建一个服务;req表示请求,request; res表示响应,response

 

if(req.url=="/fang"){

fs.readFile("./test.html",function(err,data){

 

res.writeHead(200,{"Content-type":"text/html;charset=UTF-8"});===>设置HTTP头部,状态码是200,文件类型是html,字符集是utf8

res.end("哈哈哈哈,我买了一个iPhone" + (1+2+3) + "s")

 

})

}else if(req.url=="/2.jpg"){===>请求一个图片,需要把图片静态出来

fs.readFile("./2.jpg",function(err,data){

res.writeHead(200,{"Content-type":"image/jpg"});

res.end(data)

})

}else{

res.writeHead(404,{"Content-type":"text/html;charset=UTF-8"});

res.end("没有这个页面")

}

});

 

server.listen(3000,"127.0.0.1");===>运行服务器,监听3000端口(端口号可以任改)

 

 

四、http

设置mime类型:res.writeHead(200,{"Content-type":"text/html;charset=UTF-8"})

输出请求地址:res.url(所有的路由设计都是通过req.url来实现的)

识别url用到的模块:url模块querystring模块

url模块(提交参数true 就相当于是querystring):

用户输入地址(不包括问号后边的内容):url.parse(req.url).pathname;

问号后边的内容:url.parse(req.url).query;==>url.parse(req.url,true).query; 输出的是对象 

URL 的完整的小写的主机部分(包括端口号):url.parse(req.url).host

完整的url:url.parse(req.url).href

完整的主机部分:url.parse(req.url).host

获取端口号:url.parse(req.url).port

把url对象装换成url字符串:url.format()

五、fs

异步IO

fs.rename(oldname,newname,callback):修改文件名字

fs.readFile:读取文件

fs.readFile("./test/1.txt",function(){err,data}{

if(err){throw err}

res.end(data);

})

fs.stat:检测文件状态

fs.stat("./album/bbb",function(err,stats){

stats.isDirectory()==>判断是不是文件夹

})

fs.stat返回的是一个对象实例,提供了isFile(判断文件),isDirectoory(判断文件夹),isBlockDevice等方法,size,ctime,mtime等属性

fs.readdir:读取文件夹中所有的文件

fs.mkdir:异步创建文件夹

fs.rmdir:删除文件夹

不正确

fs.readdir("./album",function(err,files){

console.log(files)==>files是个数组,表示./album这个文件夹中的所有东西,包括文件、文件夹

for(var i=0; i<files.length; i++){

var thefilename=files[i];

fs.stat("./album/"+thefilename,function(err,stats){

if(stats.isDirectory()){

wenjianjia.push(thefilename)

}

})

}

})

正确写法把异步变成同步(递归思想)

fs.readdir("./album",function(err,files){

var wenjianjia=[];

(function iterator(i){

if(i==files.length)return;

var fileName=files[i];

fs.stat('./album/'+fileName,function(err,stats){

if(stats.isDirectory()){

wenjianjia.push(fileName)

}

iterator(i+1)

})

})(0)

})

六、路由

根据不同的请求路径返回不同的数据

 

 

七、path(mime类型)

返回拓展名:path.extname(p)

function getMime(extname){

swich(extname){

case ".html":

return "text/html";

break;

case ".jpg":
 
return "image/jpg";

break;

}

}

八、模块

模块引用是从当前模块出发,但是用fs读取模块的时候是从更目录查找 就找不到,解决方法 使用个目录__dirname

顶级作用域

js文件中,可以用exports暴露很多东西,使用者只需要require一次,相当于增加了顶层变量,所有的函数,变量都要从这个顶层变量走

js文件和js文件之间有两种合作的模式

1)某一个js文件中,提供了一个函数,共别人使用,只需要暴露函数就行了:exports.msg=msg

2)某一个js文件,描述了一个类。module.exports=People

注:在require中没有写'./',不是相对路径,例如:“main.js”,是一个特殊的路径,默认是从node_modules;如果引用‘./’和‘.js’都不写,默认是引用文件夹

每个模块文件中,推荐都写一个package.json文件,这个文件的名字不能改,node将自动读取里边的配置,有一个main项,设置入口文件:

{

 

name:'bar',

"version":'1.0.1',

"main":'app.js'

 

}

注:package.json文件,要放到模块文件夹的根目录去

 

九、npm

 

http://www.npmjs.cim

如果要配置一个模块

下载模块:npm install 包命

可以用package.json管理依赖

1)生成package.json:npm install

“dependencies”:{依赖的包名}

2)生成package.json以后,就创建了依赖,当把模块删除的时候,就可以在本地下载所需模块 

npm.init

 

十、http请求

处理post请求的两种方法(这两种方法包含了两个方法:data,end):on、addListener 

解析前台发来的数据,解析字符串中的键值对:querystring (查询字符串)

上传图片和视频:formidable        

返回当前目录的上一级:path.resolve(__dirname,'..')

处理地址栏参数,一般用于get请求:url

enctype="multipart/form-data"

修改文件的名字fs.rename("./1.txt","./2.txt")

post请求:

接收post请求 

 if(req.url=="/dopost"&&req.method.tolowerCase()=="post"){

var alldata='';

req.addListener('data',function(chunk){==>chunk输出的格式Buffer

alldata+=chunk

console.log(chunk)

})

req.addListener('end',function(){

console.log(alldata.toString());

var dataString=alldata.toString()

res.end("success");

})

}

 

十一、express

 

npm install express

 

中间件

获取参数的四种方法:

req.body:不是nodejs里边提供,需要载入body-parser中间件才可以使用(此方法通常解析post请求的数据)

使用:

 

var express=require('express');
var bodyParser=require('body-parser');
var app=express();
app.use(bodyParser.urlencoded({extended:true}));
app.post('/teacher',function(req,res){
    res.end(req.body.name);
});
app.listen(3000,'127.0.0.1');
 

 

req.query:nodejs中默认提供,不需要载入中间件(此方法用来解析get请求的数据)

req.params:nodejs默认提供,不需要载入其他中间件(包含路由参数,在URL的路径部分)

req.param():被弃用

express的基本雏形:

var express=require('express');

var app=express();

app.set('view engine','ejs');

app.get('/',function(req,res){

res.render('haha',{

news:['aa','bb','']

})

})

'#'提交是提交给自己

 

 

 

 

取得 GET Request 的 Query Strings:

GET /test?name=fred&tel=0926xxx572
app.get('/test', function(req, res) {
    console.log(req.query.name);
    console.log(req.query.tel);
});

如果是表单且是用 POST method:

<form action='/test' method='post'> 
    <input type='text' name='name' value='fred'> 
    <input type='text' name='tel' value='0926xxx572'> 
    <input type='submit' value='Submit'> 
</form>
app.post('/test', function(req, res) {
    console.log(req.query.id);
    console.log(req.body.name);
    console.log(req.body.tel);
});

十二、路由

 

当用get访问一个网址

app.get('网址',function(){

})

当用post访问一个网址

app.post('网址',funtion(){

})

如果想处理这个网址的任何method的请求,

app.all('网址',function(){

})

注:这里的地址不分大小写,所有的参数‘?’都已经被忽略

正则表达式可以被使用。正则表达式中,未知部分用圆括号分组,然后可用req.params[0]、[1]得到req.params类数组对象

app.get(/^\/student\/([\d]{10})$/,function(req,res){

res.send("学生信息,学号"+req.params[0]);

})

冒号是更推荐的写法

app.get('/student/:id',function(req,res){

var id=req.params["id"];

var reg=/^[\d]{6}$/;

if(reg.test(id)){

res.send(id)

}else{

res.send("请检查格式")

}

})

表单可以自己提交到自己

app.get("/",function(req,res){

res.render("form")

})

app.post("/",function(){

//将数据提交到数据库

res.send("成功")

})

restful路由设计:同一个网址,不同的访问方式,执行不同的命令  ==>适合app开发使用

请求:/studednt

get:读取学生信息

add:添加学生信息

delete:删除学生信息

 

十二、中间件

 

如果get、post回调函数中,没有next参数,那么就匹配上第一个路由,就不会再往下匹配了

如果想往下匹配,需要写next()

app.get('/',function(req,res){

console.log(1);

next();

})

app.get('/',function(req,res){

console.log(2)

})

路由get、post这些东西,就是中间件,中间件讲究顺序,匹配上第一个以后,就不会再往后匹配,next函数才能继续

app.use()也是一个中间件,与get和post不同的是,他的网址不是精确匹配的,而是能够有小文件夹扩展的

注:当use不写路径的时候,实际上就相当于'/',就是所有网址都可以访问,

app.use('/admin',function(req,res){

res.write(req.orginalUrl)      ==>/admin/aa/bb/cc/dd

res.write(req.baseUrl);   ==>/admin

res.write(req.path);  ==>/aa/bb/cc/dd

res.end("你好")

})

静态服务 (第三方服务):app.use(express.static('./public'))======>app.use('/jintai',express.static('./public'))  这样写静态文件路径从'jintai'出发

app.use()就给我们增加了一些特定功能的便利场所

实际上app.use()的东西,基本上都是第三方得到的

render和send不同点

1、大多数情况下,渲染内容有res.render(),将会根据views中的模板文件进行渲染,如果不想使用views文件夹,想自己设置文件夹的名字,那么app.set('view engine','ejs')

2、如果想写一个快速测试页,当然可以使用res.send(),这个函数将根据内容,自动帮我们设置了Content-Type头部和200状态码,send()只能用一次,和end一样,可以设置mime类型

3、如果想使用不同的状态码:res.status(404).send('sorry ,we  can not defined')

4、如果想使用不行的Content-Type:res.set('Content-Type','text/html')

get和post请求

get请求的参数在url中,在原生的node中,需要使用url模块来识别参数字符串,在express中,不需要使用url模块了,可以直接使用req.query对象

post请求在express中不能直接获取,必须使用body-parser模块,使用后,将可以用req.body得到参数,但是如果表单中含有文件,那么还需要使用formadable模块

十三、MVC

 

文件目录:

controller:控制器 路由

models:模型

views:视图

uploads:图片存放地址

public:静态文件目录

node_modules:依赖文件

app.js:入口文件

设置入口文件:在package.json中{'main':'router.js'}

错误

res.render('index',{

'name':studentgetById('123').name

})

正确

student.studentgetByXuehao('123',function(detail){

res.render('index',{

'name':detail.name

})

})

异步和同步读取文件夹

异步读取文件(递归思想)

fs.readdir('./uploads/',function(err, files){
        (function iterator(i){
            if(i==files.length){
                callback(allAlbum);
                return;
            }
            fs.stat('./uploads/'+files[i],function(err, stats){
                console.log(stats)
                if(stats.isDirectory()){
                    allAlbum.push(files[i])
                }
                iterator(i+1)
            })
        })(0)
  });

 

同步步读取文件

fs.readdir('./uploads/',function(err, files){
        (function iterator(i){
            if(i==files.length){
                callback(allAlbum);
                return;
            }
            fs.stat('./uploads/'+files[i],function(err, stats){
                console.log(stats)
                if(stats.isDirectory()){
                    allAlbum.push(files[i])
                }
                iterator(i+1)
            })
        })(0)
    });

返回当前目录的上一级:path.resolve(__dirname,'..')

 

十四、NoSQL

非结构型数据库,没有行、列的概念,用json来存储数据。

 

集合就相当于“表”,文档就相当于“行”

文档就是json,上下文语境中,也是javascript范畴,所以我们的数据库也是js范畴的东西

NoSQL不是银弹,没有资格挑战老牌数据库,还是特定情况下,是适合的

 

十五、mongoDB

win7系统需要在安装补丁,KB2731284

装好文件夹:C:\Program Files\MongoDB

设置环境变量:C:\Program Files\MongoDB\Server\3.2\bin

开机:mongod  --dbpath 数据库文档所在的文件夹

使用数据库:mongo 链接数据库

导入数据:mongoimport

列出所有数据库:show dbs

使用某个数据库:use 数据库名字

如果use一个不存在的数据库,就是新建数据库

查看当前所在数据库:db

插入数据(student就是所谓的集合,集合中存放着许多json):db.student.insert({"name":"xiaoming","age":12})

列出当前集合:show collections

列出集合中的json:db.student.find();

精确查找:db.student.find({'name':'xiaoming'});

多个条件匹配:db.student.find({'name':'xiaoming','age':12});

大于50的集合:db.student.find({'score.yuwen':{$gt:50}});

或关系查找:db.student.find($or:[{"age":9},{"age":11}]);

查找完之后大点调用sort,表示什降排序,如果前边的一样按后边的来排:db.student.find().sort({'borough':1,'adress':1})

向集合中插入一条数据:db.student.insert({"name":"xiaozhang","age":11});

删除数据库,删除当前数据库:db.dropDatabase();

导入数据:mongoimport --db test(数据库的名字) --collection restaurants(向往哪个集合中导入) --drop(把集合清空) --file dataset.json导入的文件       

改变数据(只能改变一个数据):db.student.update({'name':'小明'},{$set:{'age':16}});                    

改变多个数据:db.student.update({},{$set:{'age':16}},{multi:true});

完整替换(不写$set):db.student.update({'name':'小明'},{'age':16});     

删除数据:sb.student.remove({'age':18})

只删除一个数据:sb.student.remove({'age':18},{justOne:true})

查看下一页:it

查找几条数据:db.student.find().limit(4);

略过几条数据:db.student.find().limit(4).skip(4);

显示数据库的数据状态:db.student.stats();

显示数据条数:db.student.find().count();

查看检索的过程:db.student.find().explain();

链接数据库:

mongoClient.connect(url,function(err,db){

代码执行;

db.close()

})

DAO封装:设计模式把底层的访问逻辑和业务逻辑分开

 

数据库链接:

function  _connectDB(callback){

 

mongoClient.connect(url,function(err,db){

callback(err,db)

})

 

}

增删改查

插入一条数据:

 

exports.insertOne=function (collectionName,json,callback){

_connectDB(function(err,db){

db.collection(collectionName).insertOne(json,function(err,result){

callback(err,result);

db.close();

})

})

}

查找数据:

exports.find=function(collectionName,json,callback){

_connectDB(function(err,db){

db.collection(collectionName).find(json).toArray(function(err,docs){

callback(err,docs)

})

})

}

通过查找数据,可以对数据进行分页。有两种做法

1)错误的做法:就是将所有的result都读取数组,然后进行数据操作,进行分页

2)正确的做饭:就是在数据库中,只读取这么多内容

 

exports.find=function(collectionName,json,args,callback){

 

var limit=args.pageAmount;

var skipNumber=args.page*args.pageAmount;

_connectDB(function(err,db){

db.collection(collectionName).find(json).limit(limit).skip(skipNumber).toArray(function(err,docs){

callback(err,docs)

})

})

 

}

删除数据:

expots.delete=function(collectionName,json,callback){

_connectDB(function(err,db){

 

db.collection(collectionName).deletMany(json,function(err,result){

 

callback(err,result)

 

})

})

}

修改数据:

exports.update=function(collectionName,json1,json2,callback){

 

_connectDB(function(err,db){

 

db.collection(collectionName).updateMany(json,json2,function(err,result){

callback(err,result)

})

 

})

 

}

索引:

建立索引:db.student.createIndex({'name':1});

索引不能相同:db.members.createIndex({'user_id':1},{unique:true})

好处:这样,今后通过name寻找student文档的熟读会非常快,

缺点:插入每条数据变慢了,效率低了

node建立索引:

_connectDB(function(err,db){

if(err){

console.log(err);

returen;

}

db.collection('student').createIndex({"cuisine":1},null,function(err,result){

console.log(result);

})

})

 

十六、session

cookie是在res中设置,req中读取的,第一次访问没有cookie。

cookie的存储大小有限,kv对儿。对用户课件,用户可以禁用、清除cookie、可以被篡改

cookie用来制作记录用户的一些信息,必须购买历史,猜你喜欢

http是无状态的协议,所以两次的访问,服务器不能认识到是同一个客户端的访问,就要用cookie的巧妙的解决这个问题

session不是一个天生就有的技术,而是依赖cookie,当浏览器禁用cookie的时候,或者用户清楚了cookie,登陆也消失,session比cookie不一样,session下发的是乱码,并且服务器自己缓存一些东西,下次浏览器的请求带着乱码上来,此时与缓存进行比较,看看是谁。

所以,一个乱码,可以对应无限大的数据,

任何语言中session的使用,是“机理透明”的,他是帮你设置cookie的,但是足够方便,让你感觉不到这事与cookie有关

nodejs中的session:

设置cookie失效时间:

var hour=360000;

req.session.cookie.express=new Date(Bate.now()+hour);

req.session.cookie.maxAge=hour;

 

var session=require("express-session");

app.use(session({

secrel:'keyboard cat',

resave:false,

saveUninitalized:true,

cookie:{secure:true}

}))

app.get("/",function(req,res){

if(req.session.login){

req.send('欢迎你'+req.session.username)

}else{

res.send("没有成功登陆")

}

})

app.get("/login",function(req,res){

req.session.login=true;//设置这个session

req.session.username="考拉"

res.send("你已经成功登陆")

})

 

十七、MD5

 

MD5加密是函数型加密。就是每次加密的结果一定相同,没有随机位

特点:

不管加密的文字,多长多短,永远都是32位英语字母、数组混合

哪怕只改一个字,密文都会大改

var crypto=require('crypto');

var shasum=crypto.createHash('sha1');

function md5(mingma){

var md5=crypto.createHash('md5');

var password=md5.update(mingma).digest('base64');

return password;

}

 

十八、图片裁剪(GraphiMagick)

 

下载:http://www.graphicsmagick.org/

设置全局的环境变量

http://elf8848.iteye.com/blog/382528

 

注意:后面三个7.0版本安装时必须勾选"Install legacy utilities(e.g. convert)"选项,否则依然会报错,而ImageMagick-6.2.7-6-Q16-windows-dll.exe默认安装即可


另外,ImageMagick-6.9.2-8-Q16-x64-static.exe安装时没有"Install legacy utilities(e.g. convert)"选项,安装完后会报错。

 

大家可以试试其他版本

 

gm convert danny.jpg haha.jpg 格式转换

 

gm mogrify -output-directory 文件夹-resize 320*200 *.jpg 裁剪图片

nodejs使用gm,需要安装gm包    https://www.npmjs.com/package/gm

var fs=require('fs');

var gm=require('gm');

nodejs缩略图制作

图片缩放:

gm('./danny.jpg')

.resize(50,50,"!")//“!”强制变成50*50

.write('./danny2.jpg',function(err){

if(err){

console.log(err)

}

})

图片裁剪:

gm('/path.to/my/img.jpg')

.flip()

.magnify()

.rotate('green',45)

.blur(7,3)

.crop(300,300,150,130)//裁剪的坐标 x,y,w,h

.edge(3)

.write('path/to/crazy.jpg',function(err){

if(!err)console.log('crazytown has arrived')

})

 

十九、Mongoose

 

 

mongoose 4.11.0以后使用:mongoose.connect("mongodb://localhost/mongoose",{useMongoClient: true});

module.exports:直接将函数暴露
 
exports:将行数名暴露
是一个将javascript对象与数据库产生关系的一个框架,操作对象,就是操作数据可了:对象产品了,同时也持久化了

 

这个思路是java三大框架SSH中的Hibernate框架的思路。彻底改变了人们使用数据库的方式。

http://mongoosejs.com

//引包,并不需要引用mongodb这个包

var mongoose=require('mongoose');

 

mongoose.Promise = global.Promise;//解决报错  2.4以上

 

 

 

//链接数据库,haha是数据库名字

mongoose.connect('mongodb://localhost/haha');

//创建了一个模型

var Cat=mongoose.model('Cat',{name:String});

//实例化一只猫

var kitty=new Cat({name:'Zildjian'});

//保存到数据库

kitty.save(function(err){

console.loh('保存')

})

mvc

//mongoose数据库链接

var mongoose=require('mongoose')

var db=mongoose.createConnection('mongodb://127.0.0.1:2017/haha')

//

db.once('open',function(callback){

console.log('数据库成功链接')

})

//Schema结构

var mongooseSchema=new mongoose.Schema({

username:{type:String,default:'匿名用户'},

title:{type:String},

content:{type:String},

time:{type:Date,default:Date.now},

age:{type:Number}

})

//基于shemale创建的

var student=db.model('Student',mongooseSchema)

//向外暴露

module.exports=mongooseSchema;

//app.js实例化(2种方法)

var xiaoming=new mongooseSchema({'name':'小明','age':12,'sex':'男'})

xiaoming.save(function(){

console.log('存储成功')

})

Student.create({'name':'小红','age':12,'sex':'女'},function(err,result){

console.log('创建成功')

})

//创建静态方法

mongooseSchema.statics.zhaoren=function(name,callback){

return this.model('student').find({name:name},callback)

}

//创建修改的静态方法

 

mongooseSchema.statics.xiugai=function(conditions,update,options,callback){

this.model('Student').update(conditions,update,options,callback)

 

}

//创建对象方法

 

 

 

mongooseSchema.methods.findSimilarTypes=function(callback){

this.model('Student').find({type:this.type},callback)

 

}

 

 

 

methods和statics的区别

 

区别就是一个给Model添加方法(statics),一个给实例添加方法(methods);调用的方式不一样,statics直接model调用,methods实例直接调用

 

二十、socket

 

http是没有状态的,服务器只会响应来自客户端的请求,但是他与客户端之间不具备持连接

长轮询:客户端没个很短的时间就会向服务器发送请求,查看是否有新的消息,轮询的速度快,浪费性能

长连接:客户端只请求一次,服务器会将连接持续,不会返回结果,服务器有了新数据,就将数据发回来,又有了数据就将数据发回来,而一直保持挂起状态。这种做法也造成了大量的性能浪费。

websocket协议能够让浏览器和服务器全双工通信,互相的,服务器也能主动通知客户端了。

websocket的原理非常简单,利用http请求产生握手,http头部中含有websocket协议的请求,所以握手之后,二者转用TCP协议进行交流(QQ的协议)

websocket协议,需要浏览器的支持和服务器的支持:

浏览器:Chrome4、火狐4、ie10、Safari5

服务器:Node0、Apach7.0.2、Nginx1.3

Node.js上需要写一些程序,来处理TCP请求

Socket.IO

 

 

 

 

 

 

 

 

 

 

 

 

后注、命令行

dir查看完整目录

可以让其他的用户访问此程序:server.listen(8080,"本机的ip")

处理favicon.ico: if(req.url=="/favicon.ico")return;

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值