node中Express的use深入理解

Express的API

现在学node,不来点Express,都不好意思给人打招呼。但是,我刚接触的时候,觉得好多API,感觉乱糟糟的,没办法,大脑容量不够。不过有一样东西叫地铁,在上面可以让人想清楚很多事情(-_-!

先来一段最简单的node版hello world

var http = require('http');http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');}).listen(1337, '127.0.0.1');

上面这段代码来自nodejs的官网,非常简单,就是来一个请求,就用传给createServer的匿名函数来处理请求。

下面来看看使用Express的代码

var app = express();//...中间忽略http.createServer(app).listen(app.get('port'), function(){
    console.log('Express server listening on port ' + app.get('port'));});

对比可以看出,执行express()后,会返回一个函数,赋值给app,app的签名应该为

function(req,res){//...}

然后请求都会被app这个函数处理(因为这个app是执行express后的结果,下面将不加区分的使用app和express两个词)。

可以认为,在express内部,有一个函数的数组,暂时叫这个数组tasks,每来一个请求express内部会依次执行这个数组中的函数(这里说依次并不严谨,每个函数必须满足一定条件才行,这个后面说),应该可以想到,在这个函数数组里,每个函数的签名应该像下面那样

function(req,res){//...}

但是,实际上是

function(req,res,next){//...}

这个next,是指下一个函数。后面我们会写一些试验来体验一下这个next,先总结一下:

对于一个典型的使用express的app.js(这个满大街都是代码,就不贴了),做了以下几件事

  • 1.导入相关模块
  • 2.执行过 var app = express() 后,
    • 使用app.set 设置express内部的一些参数(options)
    • 使用app.use 来注册函数,可以简单的认为是向那个(被我叫做)tasks的数组进行push操作
  • 3.通过http.createServer 用app来处理请求

试验1. 向express中注册自定义函数

注册进express中的函数,需要满足(请见下面更正)

1.长成下面这个样子

function(req,res,next){
    //...我们自己的逻辑    next();}

2.app.use(customerFunc) 要写在下面两句的前面

app.use(app.router);app.use(express.static(path.join(__dirname, 'public')));

关于第2点,是因为路由后或请求静态资源后,一次请求响应的生命周期实质上已经结束,加在这后面进行请求处理,没有任何意义。

关于第1点,写点代码就好了,

app.use(function(req,res,next){
    console.log("111");
    next();});

如果不写next(),那么后面注册的函数就不会执行,运行试一下就知道了。

再来一个:

app.use(function(req,res,next){
    console.log('111');
    next();
    console.log('222');});app.use(function(req,res,next){
    console.log("333");
    next();});

那么控制台的输出的顺序是:111 333 222

试验二 next()的工作原理

整个处理请求的模型还是很简单的,在理解的上面的过程后,能不能不借助express,自己实现上面的过程呢,主要是怎么处理next()那一块

我写了一个简单的实现,测试可用,这里和大家进行讨论,主要是 第5行 起的那个函数,虽然很简短,还是花了一些时间(囧

var http = require('http');function express(){
    var funcs = [];

    var expr = function(req,res){
        var i = 0;
        function next(){            
            var task = funcs[i++];
            if(!task) return;
            task(req,res,next);
        }
        next();
    }
    expr.use=function(f){
        funcs.push(f);
    }
    return expr;}var app = express();app.use(function(req,res,next){
    console.log('haha');
    next();});app.use(function(req,res,next){
    console.log('hehe');
    next();});app.use(function(req,res){
    res.end("there is nothing happened");});http.createServer(app).listen('3000', function(){
  console.log('Express server listening on port 3000');});

启动服务后,每来一个请求,控制台会依次输出haha hehe,然后浏览器是there is nothing happened

当然如果要更深一步,可以去看原代码,实际上这一部分的主要代码是在connect中的,在connect/lib/proto.js 这个源文件中,主要是app.use,和app.handle 两个函数中

更正:

上面说,自定义的函数应该满足两个条件,一般使用是那样。但是,也可以两个都不满足。。。比如,自定义函数可以是4参数的,放在最后做通用error处理。在下面两句之后

    app.use(app.router);app.use(express.static(path.join(__dirname, 'public')));

可以加一个

    app.use(function(err,req,res,next){
          if(err){
                 //自己的处理错误的逻辑                 console.log(err.message);
                 console.log(err.stack);
                 res.end('404')  
          }
    })

原文发布于微信公众号 - 交互设计前端开发与后端程序设计(interaction_Designer)

原文发表时间:2017-07-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏未闻Code

正则表达式re.sub替换不完整的问题现象及其根本原因

问题的起因来自于一段正则替换。为了从一段HTML代码里面提取出正文,去掉所有的HTML标签和属性,可以写一个Python函数:

14520
来自专栏大内老A

一句代码实现批量数据绑定[下篇]

《上篇》主要介绍如何通过DataBinder实现批量的数据绑定,以及如何解决常见的数据绑定问题,比如数据的格式化。接下来,我们主要来谈谈DataBinder的设...

23950
来自专栏CSDN技术头条

深入讲解 Vue 中实现原理

随着 Vue2.0 的发布,前端入门的要求也越来越低,已至于 Vue 已经成为一个前端的标配,最近也面了很多前端开发工程师,发现大部分都停留在用的阶段上,建议大...

12420
来自专栏前端架构与工程

【翻译】JavaScript内存泄露

我们在进行JavaScript开发时,很少会考虑内存的管理。JavaScript中变量的声明和使用看起来是一件很轻松的事,底层的细节处理交给浏览器去做就好了。 ...

30260
来自专栏macOS 开发学习

Swift 日常使用Tip

Swift中的Struct都有个系统提供默认的包含所有成员遍量的init方法,如果我们添加自定义的init方法时,系统默认提供的就会消失,如果需要既可以保留系统...

8730
来自专栏面朝大海春暖花开

jquery实用的一些方法

当你想实现最基本的加减法的时候,对于转换number实用Number(str)即可

9510
来自专栏腾讯IVWEB团队的专栏

你可能不知道的 ECMAScript 2016 的变化(英译)

与 ECMAScript 6(也称为ECMAScript 2015)相比,ECMAScript 2016 是对 JavaScript 语言规范的一个小更新。 ...

22800
来自专栏极客编程

mootools入门

MooTools是一个简洁,模块化,面向对象的开源JavaScript web应用框架。

11420
来自专栏difcareer的技术笔记

关于EGL与示例代码[转]

OpenGL ES的javax.microedition.khronos.opengles 包定义了平台无关的GL绘图指令,EGL(javax.microedi...

9030
来自专栏编程

如何用Vim提高开发效率

背景 虽然笔者是Android开发工程师,但也接触过各种IDE(不限于Android开发)。不同的IDE往往都有不同的快捷键,我们总不能对每种IDE都进行配置吧...

25480

扫码关注云+社区

领取腾讯云代金券