美文网首页
NodeJS——Connect

NodeJS——Connect

作者: Eylen | 来源:发表于2018-03-07 15:12 被阅读0次

Connect是一个框架,它使用被称为中间件的模块化组件,以可重用的方式实现web程序的逻辑。在Connect中,中间件组件是一个函数,它拦截HTTP服务器提供的请求和响应,执行逻辑,然后,或者结束响应,或者把它传递给下一个中间件组件。Connect用分配器把中间件“连接”在一起。
(Express构建在Connect之上的更高层的框架,添加了更多糖衣)


  • ex1 最小的Connect程序
var connect = require("connect");
var app = connect();
app.listen(3000);

所有HTTP请求结果:404 Not Found


Connect 工作机制

  1. Connect分配器会依次调用所有附着的中间件组件,直至其中一个组件决定响应该请求,如果知道中间件组件列表末尾还是没有组件决定响应,程序会返回404作为响应。(ex1这个裸程序没有中间件组件,故会返回404 Not Found状态码响应他接收到的所有HTTP请求。)

  2. Connect中,中间件组件是一个JS函数,接收3个参数
    a. 请求对象(req)
    b. 响应对象(res)
    c. 通常会命名为next的参数:一个回调函数,表明当前中间件已经执行完毕,可以执行下一个中间件组件

  • ex2 简单的 hello world + 日志log
var connect = require("connect");
var app = connect()
          .use(logger)
          .use(hello)
          .listen(3000);

function logger(req, res, next) {
    console.log(req.method + ' ' + req.url);
    next(); //执行下一个中间件
}

function hello(req, res) {
    res.setHeader('Content-type', 'text/plain');
    res.end("hello world");
}

  • ex3 中间件的顺序问题
var connect = require("connect");
var app = connect()
                  .use(hello)
          .use(logger)
          .listen(3000);

function logger(req, res, next) {
    console.log(req.method + ' ' + req.url);
    next(); //执行下一个中间件
}

function hello(req, res) {
    res.setHeader('Content-type', 'text/plain');
    res.end("hello world");
}

在ex3中,先执行了hello的中间件,响应了HTTP的请求,同时没有调用next(),控制权不会回到分配器去调用下一个中间件,所以logger中间件不会调用。
注意:当一个中间件组件不调用next()时,命令链中的其他中间件都不会被调用。


挂载

可以给中间件或整个程序定义一个路径前缀。通过使用挂载,可以像在根层次中编写中间件一样(/根req.url),并且可以不修改代码就将他放在任何路径前缀上。挂载还将只对路径前缀内的请求调用中间件或程序。

  • ex4 验证用户和用户管理区
var connect = require("connect");
var app = connect()
          .use(logger)
          .use('/admin',restrict) //restrict组件用于验证用户,只在/admin的路径上调用
          .use('/admin',admin) //admin组件用于管理用户,只在/admin的路径上调用         
          .listen(3000);

创建可配置中间件——闭包

  • ex5 可配置中间件基本结构
function setup(options){
  return function(req, res, next){
    //中间件逻辑
  }
}
app.use(setup({some: 'options'}));



在ex2中有一个简单的logger中间件,在代码里面已经写死了将会打印出 req.method 、req.url,不利于代码的重用,无法应对需求的变化

function logger(req, res, next) {
    console.log(req.method + ' ' + req.url);
    next(); //执行下一个中间件
}
  • ex6 可配置的logger中间件
function setup(format){
    var regexp = /:(\w+)/g;
    return function logger(req, res, next){
        var str = format.replace(regexp, function(match, property) { 
        /*
            当string.replace()的第二个参数为字符串时,则替换匹配到的第一个字符串

            当string.replace()的第二个参数为函数时,则替换每一个匹配到的字符串
            有4个参数
            第一个参数(match)为正则表达式捕获的字符串,如:method、:url
            第二个参数(property)为捕获括号所捕获的字符串,如method、url
            第三个参数为正则表达式匹配到的每段字符的第一个字符的索引
            第四个参数为匹配的字符串主体
        */
            return req[property];
        });
        console.log(str);
        next();
    }
}

module.exports = setup;
  • ex7 简单的路由中间件
    ./middleware/router.js
var parse = require('url').parse;
module.exports = function route(obj) {
    return function(req, res, next) {
        if (!obj[req.method]){
            next();
            return;
        }
        var routes = obj[req.method];
        var url = parse(req.url);
        var paths = object.Keys(routes);

        for(var i = 0; i < paths.length; i++){
            var path  = paths[i]; // /user/:id
            var fn = routes[path];
            // /user/:id -> /user/([^\\/]+)
            path = path.replace('/\//g','\\/').replace('/:(\w+)/g','([^\\/]+)');
            var re = new RegExp('^' + path + '$'); //   ^/user/([^\\/]+)$
            var captures = url.pathname.match(re);  // ['/user/12',12,...]
            if(captures){
                var args = [req, res].concat(captures.slice(1));  //concat 数组连接; slice(start, end)返回数组start到end的元素的数组
                fn.apply(null, args);
                return;
            }
        }
        next()
    }
};

使用 router 中间件

var connect = require("connect");
var router = require('./middleware/router');
var routes = {
    GET:{
        '/users':function(req, res) {
            res.end("Mike","Jay","Kim");
        }
        '/user/:id':function(req, res, id) {
            res.end('user ' + id);
        }
    },
    DELETE:{
        '/user/:id':function(req, res, id) {
            res.end('deleted user ' + id);
        }
    }
}

connect()
    .use(router(routes))
    .listen(3000);

处理程序错误的中间件

  • ex8
function erorHandler() {
    var env = process.env.NODE_ENV || 'development'; //在不同的服务器环境中切换,比如生产和开发环境
    return function(err, req, res, next) {
        res.statueCode = 500;
        switch(env){
            case 'development':
                res.setHeader('Content-type', 'application/json');
                res.end(JSON.stringify(err));
                break;
            default:
                res.end('server error');
        }
    }
}

相关文章

网友评论

      本文标题:NodeJS——Connect

      本文链接:https://www.haomeiwen.com/subject/bpndfftx.html