node.js原生后台进阶(二)

上一章讲到怎么样用原生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();
})
原文地址:https://www.cnblogs.com/amiezhang/p/8134164.html