node 中间件介绍

nodejs提供了http模块,自身就可以用来构建服务器,而且http模块是由C++实现的,性能可靠。今天我们讲下node中间件。

http基本用法

http.createServer函数用来创建一个HTTP服务器,并将 requestListener 作为 request 事件的监听函数。
http.createServer([requestListener])
由于该方法属于http模块,使用前需要引入http模块(var http= require(“http”) )
接收参数:
requestListener   请求处理函数,自动添加到 request 事件,函数传递两个参数:

    req  请求对象,想知道req有哪些属性,可以查看 “http.request 属性整合”。

    res   响应对象 ,收到请求后要做出的响应。想知道res有哪些属性,可以查看 “http.response属性整合”。
例:

var http = require('http')
http.createServer(function(req,res) {
    res.writeHead(200,{
        "content-type":"text/plain"
    })
    res.write("hello node")
    res.write("hello node1")

    res.end("dkkddkdk")
}).listen(3000)

Express

Express 是一个保持最小规模的灵活的 Node.js Web 应用程序开发框架,为 Web 和移动应用程序提供一组强大的功能。

一 创建express服务

let express = require('express');
let app = express();
// 最基本的模型
app.get('/',function(req,res){
    res.end('ok');
});
app.listen(3000);

二 配置路由

语法:
app.(path,[callback...],callback)

app.get('/',function(req,res){ res.send("Server Root"); }); app.post('/',function(req,res){ res.send("Save Page"); });

三 中间件

express支持的中间件组件如下:
1.应用级别的中间件

app.get("/", function (req, res,next) {
    console.log("匹配成功");
    next()
})

2.路由中间件

app.get("/", function (req, res,next) {
    console.log("匹配成功");
    next()
})

app.get("/", function (req, res) {
    var list = [1, 6, 9, 8, 55, 66, 45]
    res.render('index', {
        "list": list
    })
})

其他中间件

  • static:允许express服务器以流式处理静态文件的GET请求。这个中间件是Express内置的,它可以通过express.static()访问。
  • express-logger:实现一个格式化的请求记录器来跟踪对服务器的请求
  • basic-auth-connect:提供对基本的HTTP身份验证的支持。
  • cookie-parser:你可以从请求读取cookie并在响应中设置cookie
  • cookie-session:提供基于cookie的会话支持
  • express-session:提供了一个相当强大的会话实现
  • body-parser:把POST请求正文中的JSON数据解析为req.body属性
  • compression:对发给客户端的大响应提供Gzip压缩支持
  • csurf:提供跨站点请求伪造保护。

KOA

简单应用

const Koa = require('koa'); 
const app = new Koa();
app.use(async ctx => { ctx.body = 'Hello World'; }); app.listen(3000);

级联

Koa 的中间件通过一种更加传统(您也许会很熟悉)的方式进行级联,摒弃了以往 node 频繁的回调函数造成的复杂代码逻辑。 然而,使用异步函数,我们可以实现"真正" 的中间件。与之不同,当执行到 yield next 语句时,Koa 暂停了该中间件,继续执行下一个符合请求的中间件('downstrem'),然后控制权再逐级返回给上层中间件('upstream')。

const Koa = require('koa'); 
const app = new Koa(); // x-response-time 
app.use(async (ctx, next) => { 
    const start = Date.now(); 
    await next(); 
    const ms = Date.now() - start; 
    ctx.set('X-Response-Time', `${ms}ms`); 
}); // logger 
app.use(async (ctx, next) => { 
    const start = Date.now();
    await next(); 
    const ms = Date.now() - start;
    console.log(`${ctx.method} ${ctx.url} - ${ms}`); 
}); 
// response 
app.use(async ctx => { 
    ctx.body = 'Hello World'; 
});

koa-router 路由管理模块的使用

const Koa = require('koa'); 
// Koa 为一个class 
const Router = require('koa-router') // koa 路由中间件 const app = new Koa(); 
const router = new Router(); // 实例化路由 // 添加url router.get('hello:name', async (ctx, next) => { 
    var name = ctx.params.name; // 获取请求参数 
    ctx.response.body = `
Hello, ${name}!
`; }); router.get('/', async (ctx, next) => { ctx.response.body = '
Index
'; }); app.use(router.routes()); app.listen(3333, () => { console.log('This server is running ') })

KOA与Express比较

Express和Koa都是基于Nodejs平台的web框架,也是目前比较常见的用于快速开发web服务的框架,且两者都是基于middleware的方式去处理客户端请求,那么两者有何区别呢?
简单点说就是,“Express是直线型,Koa是洋葱模型”。

我们来看下下面代码

// for express example
const express = require('express');

const app = express();

async function cb1(req, res, next) {
    console.log('>>>>>>cb1');
    await next();
    console.log('<<<<< {
        setTimeout(resolve, 500);
    }).then(() => {
        console.log('>>>cb2<<<');
        res.send('hello world');
    });
}

app.use('/', [cb1, cb2]);
app.listen(3000);
// for koa2 example
const koa = require('koa2');

const app = new koa();

async function cb1(ctx, next) {
    console.log('>>>>>>cb1');
    await next();
    console.log('<<<<< {
        setTimeout(resolve, 500);
    }).then(() => {
        console.log('>>>cb2<<<');
        ctx.body = 'hello world';
    });
}

app.use(cb1);
app.use(cb2);
app.listen(3000);

express结果

>>>>>>cb1
>>>>>>cb1
>>>cb2>>>

KOA结果

>>>>>>cb1
>>>cb2<<<
<<<<<

从上面的例子可以看出,当middleware为异步函数时,Express和Koa的执行流程是不同的。Express的返回结果并不是我们设想中的结果,是什么原因导致的行为差异呢?下面,让我们一起来简单的分析下Express和Koa中执行middleware部分的源码片段。
在Express中,执行middleware的逻辑代码主要位于_lib/router/route.js_和_lib/router.layer.js_文件:

// route.js
Route.prototype.dispatch = function dispatch(req, res, done) {
  var idx = 0;
  var stack = this.stack;
  if (stack.length === 0) {
    return done();
  }

  var method = req.method.toLowerCase();
  if (method === 'head' && !this.methods['head']) {
    method = 'get';
  }

  req.route = this;

  next();

  function next(err) {
    // signal to exit route
    if (err && err === 'route') {
      return done();
    }

    // signal to exit router
    if (err && err === 'router') {
      return done(err)
    }

    var layer = stack[idx++];
    if (!layer) {
      return done(err);
    }

    if (layer.method && layer.method !== method) {
      return next(err);
    }

    if (err) {
      layer.handle_error(err, req, res, next);
    } else {
      layer.handle_request(req, res, next);
    }
  }
};


//layer.js
Layer.prototype.handle_error = function handle_error(error, req, res, next) {
  var fn = this.handle;

  if (fn.length !== 4) {
    // not a standard error handler
    return next(error);
  }

  try {
    fn(error, req, res, next);
  } catch (err) {
    next(err);
  }
};

Layer.prototype.handle_request = function handle(req, res, next) {
  var fn = this.handle;

  if (fn.length > 3) {
    // not a standard request handler
    return next();
  }

  try {
    fn(req, res, next);
  } catch (err) {
    next(err);
  }
};

在Koa2中,执行middleware的逻辑代码主要位于_koa-compose/index.js_文件:

function compose (middleware) {
  if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
  for (const fn of middleware) {
    if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
  }

  /**
   * @param {Object} context
   * @return {Promise}
   * @api public
   */

  return function (context, next) {
    // last called middleware #
    let index = -1
    return dispatch(0)
    function dispatch (i) {
      if (i <= index) return Promise.reject(new Error('next() called multiple times'))
      index = i
      let fn = middleware[i]
      if (i === middleware.length) fn = next
      if (!fn) return Promise.resolve()
      try {
        return Promise.resolve(fn(context, function next () {
          return dispatch(i + 1)
        }))
      } catch (err) {
        return Promise.reject(err)
      }
    }
  }
}

由上可知,Express中middleware的next参数是一个普通的函数对象,而Koa中middleware的next参数是一个promise对象。所以当我们挂载异步的middleware时,Express并不能像Koa一样,在middleware中使用await去等待下一个middleware执行完成之后,再执行当前middleware的后续逻辑。这就是为什么“Express是直线型,Koa是洋葱模型”的根本原因。

你可能感兴趣的:(javascript,node.js)