zoukankan      html  css  js  c++  java
  • 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





  • 相关阅读:
    java四种线程池类型以及可选择的阻塞队列
    复习-java向上转型
    synchronized 加在方法和代码块底层实现区别
    synchronized 和 lock 的区别
    hashmap-put方法过程
    mybatis-防止sql注入
    synchronized-粗略过程
    消息队列-观察者模式和发布订阅模式区别
    复习-进程的调度算法
    Chocolatey
  • 原文地址:https://www.cnblogs.com/zhangzl419/p/15322783.html
Copyright © 2011-2022 走看看