上一章讲到怎么样用原生node.js来获取GET、POST(urlencoded,formData)的参数,这一次我们更进一步,讲一下以下的点:
1.压缩(zlib)
2.流(stream)
3.路由
一、压缩
所有网站其实在发送到我们的客户端的时候,数据都是经过压缩的,不然会造成大量的流量损失,流量可都是钱啊~~~
node里面有一个模块叫zlib,是专门用来压缩数据的,而我们最常用的就是gzip
const zlib = require('zlib'); //创建gz对象,之后就可以对流进行压缩处理了 let gz = zlib.createGzip();
二、流
为什么要用流处理呢?例如之前的写法,fs.readFile是读取完整个文件才把整个文件的data输出的,这样就会造成一个机器资源使用不充分的问题:
一开始读取文件的时候,磁盘在高速工作,但是带宽却空闲着,
之后读取完文件后,带宽在忙碌传输,磁盘却空闲了。
用流来处理,就可以做到“磁盘读到多少就用带宽传多少”,充分利用服务器的资源
//创建一个读取流 let rs = fs.createReadStream(`www${pathname}`); let gz = zlib.createGzip(); //书写响应头,告诉浏览器我们的数据格式是经过压缩的gzip res.setHeader('Content-Encoding','gzip'); //读取流先传给gz,再传给响应流 rs.pipe(gz).pipe(res); rs.on('error',err=>{ //如果错误,要把之前的响应头去掉,不然浏览器会解析错误 res.removeHeader('Content-Encoding'); res.writeHeader(404); res.write('not found!!'); res.end(); })
三、路由
所谓路由,就是接口的地址入口,我们大可以这样写:
switch(pathname){ case '/login': //... break; case '/reg': //... break; default: //... break; }
不过这样写,导致路由和功能代码严重的耦合在一起,这显然不是我们想要的
node给我们提供了一个叫EventEmitter的东西,实现了在js的响应式编程
因为node.js的引用是单例的,因此我们可以先创建一个module作为全局的EventEmitter,router.js
const Event = require('events').EventEmitter; module.exports = new Event();
在server.js那加入EventEmitter的触发:
const http = require('http'); const fs = require('fs'); const router = require('./libs/router'); const url = require('url'); const zlib = require('zlib'); //在'./router/Users'上面注册了一些接口 require('./router/Users'); http.createServer((req,res)=>{ let {pathname,query}=url.parse(req.url,true); req.query = query; res.send = msg=>{ if(typeof msg!="string"&&!(msg instanceof Buffer)){ msg = JSON.stringify(msg); } res.write(msg); } //router.emit会触发对应的接口,如果事先有注册对应的接口返回true,否则返回false,我们就认为这个请求是在请求文件 if(!router.emit(pathname,req,res)){ let rs = fs.createReadStream(`www${pathname}`); let gz = zlib.createGzip(); res.setHeader('Content-Encoding','gzip'); rs.pipe(gz).pipe(res); rs.on('error',err=>{ res.removeHeader('Content-Encoding'); res.writeHeader(404); res.write('not found!!'); res.end(); }) } }).listen(8088);
做完这些,我们就可以在多个模块来“注册”接口了
const router = require('../../libs/router.js'); let users = { rick : 123456 }; //注册一个叫'/login'的接口,在这里我们还可以添加上一篇博文的东西,接收GET、POST的参数,这里我只写了接收URL上的参数 router.on('/login',(req,res)=>{ let {name,pass} = req.query; if(!users[name]){ res.send({code:1,msg:'user not found!'}) }else if(users[name]!=pass){ res.send({code:1,msg:'username or password is wrong'}) }else{ res.send({code:0,msg:'success'}) } res.end(); })