express的一些核心概念

express的一些核心概念


提纲
1、路由
2、在express中使用静态文件
3、中间件


1、路由

路由(Routing)是由一个 URI(或者叫路径)和一个特定的 HTTP 方法(GET、POST 等)组成的,涉及到应用如何响应客户端对某个网站节点的访问。
每一个路由都可以有一个或者多个处理器函数,当匹配到路由时,这些函数将被执行。

路由的定义由如下结构组成:
app.METHOD(PATH, HANDLER)。
其中:
app 是一个 express 实例;
METHOD 是某个 HTTP 请求方式中的一个;
PATH 是服务器端的路径;
HANDLER 是当路由匹配到时需要执行的函数。

我们可以从之前创建的 myapp 应用中看到,在 app.js 中有如下两行代码:

app.use('/', indexRouter);
app.use('/users', usersRouter);

这就是定义路由的代码。

在这两行代码之前,有如下的代码:

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

var app = express();

从这三行代码中可以看出,indexRouter指的是项目根目录下/routes/index.js文件,usersRouter指的是项目根目录下/routes/users.js文件

在 routes 下的 index.js文件的内容如下:

var express = require('express');
var router = <b>express.Router()</b>;
 
/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

module.exports = router;

从上面的代码中,能够看出来,路由在express中指的是Router类的对象,上面的代码先是生成了一个Router类的对象 router ,用它对/进行响应,然后导出了router对象。


2、express中使用静态文件

通过 Express 内置的 express.static 可以方便地访问项目中的静态资源文件,例如图片、CSS、JavaScript文件等。

将静态资源文件所在的目录作为参数传递给 express.static 中间件,就可以通过网址访问到静态资源文件了。

例如,假设在 public 目录放置了图片、CSS 和 JavaScript 文件,那么,为了访问这些静态资源文件,我们可以如下操作:

app.use(express.static('public'));

现在,public 目录下面的文件就可以访问了,访问方式如下:

http://localhost:3000/images/favicon.ico

注意观察这个网站,它是/下面直接是public下面文件夹的名字,而略过了public,因为public被映射为/了,那么/指的就是public了,所以。。。

如果你的静态资源存放在多个目录下面,你可以多次调用 express.static 中间件:

app.use(express.static('public'));
app.use(express.static('images'));

访问静态资源文件时,express.static 中间件会根据目录添加的顺序查找所需的文件。

http://localhost:3000/favicon.ico

所以,上面的网站访问的时候,express会先在public下查找favicon.ico,如果找到就返回了,如果没有找到,就继续从images下面去找,直到找到,或者最后都没有找到,就返回错误给客户端了。

如果你希望所有通过 express.static 访问的文件都存放在一个“虚拟(virtual)”目录(即目录根本不存在)下面,可以通过为静态资源目录指定一个挂载路径的方式来实现,如下所示:

app.use('/virtual', express.static('public'));

现在,你就可以通过带有 “/virtual” 前缀的地址来访问 public 目录下面的文件了。

http://localhost:3000/virtual/images/favicon.ico

从这里可以看出,之前app.use(express.static('public'))没有指定目录,其实这是说如果use方法中没有指定目录,默认挂载到根url /下面。


在静态资源文件中,有一个值得注意的地方,那就是添加 favicon.ico。

在express服务项目根目录下的 public/images 添加文件 favicon.ico

在app.js 在其中添加

var favicon = require('serve-favicon');
app.use(favicon(__dirname+'/public/images/favicon.ico'));

然后通过命令行安装 serve-favicon
npm install serve-favicon --save
重新启动项目
npm start
注意要清除缓存,这样我们就可以在新开的 http://localhost:3000/ 中看到网站图标favicon.ico了。


3、中间件

中间件也是express中一个很重要的概念,这里记录一下我的理解。

express的中间件从形式上看其实就是一个js的函数。

一个express服务中,一般会有多个中间件,这多个中间件可以组成一个列表。一个请求到达服务端后,这个请求会被抽象成一个req对象,这个对象会依次进入中间件列表的每一次,就是先到达第一个中间件,接受它的处理,之后进入第二个中间件,依次类推,直到所有中间件处理了这个请求,最后req对象会被送到路由处理函数中,在路由处理函数处理后,给浏览器返回一个res对象。

一个服务中的对个中间件,可以形成一个如上图所示的列表。

下面的图片是一个包含3个中间件的express服务,它包含的三个中间件分别是: middlewareA、middulewareB、middlewareC。从定义来看,它们三个其实就是3个函数,每个函数有3个参数,分别是req、res、next,req指的是代表请求的对象,res是代表响应的对象,next表示的是中间件列表中的下一个中间件。

上图中的三个中间件,被express的use方法依次添加到了中间件列表中。

当启动这个express服务后,不管流量拿起访问的是根路径 "/",还是"/a"路径,以上所有的3个中间件在每次请求中都会被执行到,这说明每次请求这个服务,服务中所有中间件都会被逐一执行。

那这样做的目的是什么呢?

咱们来实现一个需求,需要计算整个网站的pv,也就是整个网站被客户端请求了多次,如果不用中间件会如何做呢?

但是,如果想用中间件实现这个功能,应该怎么做呢?

上面使用中间件的程序中,定义了一个中间件,在这个中间件中对表示pv的变量n进行累加,这样n的值就表示服务的访问次数。

仔细对比一下这两份代码,可以看到第二份要简洁很多。第二份程序将计算访问量的代码放到中间件中,不需要再在各个路由中分别去写了,提高了复用性,逻辑表达更清晰,也增加可维护性。

这里需要注意的是,中间件的调用顺序是从上到下,每个中间件调用完成后必须调用next()方法。

中间是什么我们基本理解清楚了,那么中间件实现的原理是什么呢?我们可以通过下面的一段代码进行体会和理解。

var http = require('http');

function express() {

    var funcs = []; // 待执行的函数数组

    var app = function (req, res) {
        var i = 0;

        function next() {
            var task = funcs[i++];  // 取出函数数组里的下一个函数
            if (!task) {    // 如果函数不存在,return
                return;
            }
            task(req, res, next);   // 否则,执行下一个函数
        }

        next();
    }

    app.use = function (task) {
        funcs.push(task);
    }

    return app;    // 返回实例
}

var app = express();

function middlewareA(req, res, next) {
    console.log('中间件1');
    next();
}

function middlewareB(req, res, next) {
    console.log('中间件2');
    next();
}

function middlewareC(req, res, next) {
    console.log('中间件3');
    next();
}

app.use(middlewareA);
app.use(middlewareB);
app.use(middlewareC);

http.createServer(app).listen('3000', function () {
    console.log('listening 3000....');
});

以上代码便是express实现中间件机制的核心代码。

总结一下,可以得到如下的几个结论:

调用express函数,返回一个app实例

在express函数内部定义一个数组来存储中间件函数

在express函数内部定义一个app函数

在app函数的内部定义一个变量i保存执行的中间件的索引,就是正在执行的中间件在中间件数组中是第几个。

在app函数中定义一个next方法,这个方法通过i值自增调用中间件

在app函数内部调用next

在app函数上定义一个use方法,这个方法可以将中间件函数逐个添加进中间件数组中。

这样的话,express中间件的调用过程其实就是一个非常多的函数嵌套,形似如下代码:

中间件越多嵌套的层级越多。

这就是中间件的概念、使用方法。


中间件的分类
中间件有三种,分别是自定义中间件,内置中间件,第三方中间件,接下来我一一介绍:

(1)自定义中间件:
顾名思义,就是自己定义的中间件。就是在回调函数中写入自己需要的方法事件。例:

自定义解析post参数中间件:

//post参数解析中间件
function bodyParser(req,res,next){
    let arr = [];
    req.on("data", chunk => {
        arr.push(chunk);//将读取到的数据存储到数组中
    });
    req.on('end', () => {       //post 数据读取完毕
        let data = Buffer.concat(arr).toString();
        // console.log(qs.parse(data));
        req.body = qs.parse(data);//将读取到的post参数数据存储到request对象中body属性中
        next();//注意,一定要数据读取完毕之后,在顺延(转发)
    })
}
//自定义post参数解析中间件
app.use(bodyParser);

(2)内置中间件:

内置中间件就是express内部本来就有的,无需下载,用的时候直接使用就可以。

//使用内置中间件
app.use(express.static('public'));//指定public目录中所有内容为静态资源
app.use(express.json()); //能够处理post请求中的json数据
app.use(express.urlencoded());//能够处理post请求中的urlencodeed格式的数据

(3)第三方中间件:
第三方中间件需要下载,下载之后引入到代码中才可以使用,如:

nodemon:服务端代码一旦进行了修改,就需要重新将代码部署到服务器,这个操作非常频繁,可以通过nodemon来进行一个自动化配置和部署(热更新)
svg-captcha:图形验证码的中间件,使用该中间件,可以生产一个图形验证码
serve-favicon:用于服务器端设置favicon视觉提示,其实就是浏览器标签标题栏上的小图标。这个第三方中间件,在上面添加favicon.ico的过程已经看到应用了。
multer:multer是一个node.js中间件,用于处理多部分/表单数据,主要用于上传文件

注意:nodemon作用是进行热更新,意思是开发过程中可以不用每次改变时都重新运行服务器,会跟着你每一次保存时自动重新运行服务器,因此nodemon应该安装为开发依赖






参考文件:
1、favicon、路由、静态文件,https://blog.csdn.net/BloodyMandoo/article/details/80173575
2、Node Express框架快速入门教程,https://blog.csdn.net/qq_26087315/article/details/113783288?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_title~default-1.no_search_link&spm=1001.2101.3001.4242
3、挥刀北上公号之Express中间件的使用、原理及实现,https://mp.weixin.qq.com/s?src=11&timestamp=1632361855&ver=3331&signature=G92yMHFvqLcLzHnrX9W1luUFTRPv0fU0WUkJaicWkcPKM53ZffMzoHS02YJpVAQndZtC-4AJovvC04l3XXwvy1gaAZIGXoQ-ciXZoogmW7c9xebEVVAkG88ZpglHj1&new=1
4、中间件的分类,https://blog.csdn.net/weixin_46099005/article/details/107824014





原文地址:https://www.cnblogs.com/zhangzl419/p/15322783.html