08【Express框架】详细版 - Express框架简介,中间件, Express请求处理,express-art-template模板引擎.

    科技2026-03-17  5

    Express框架 

    目标

     能够使用Express创建web服务器 能够使用Express处理请求参数 能够使用Express处理静态资源 能够使用中间件处理请求 能够在Express中集成art-template模板引擎 Express框架简介及初体验 Express框架请求处理 express-art-template模板引擎 Express中间件

     

    1. Express框架简介及初体验

    1.1 Express框架是什么?

    1)Express是一个基于Node平台的web应用开发框架,它提供了一系列的强大特性,帮助你创建各种Web网站应用。使用原生JS代码写起来比较复杂,比较底层的;比如实现路由功能,需要对请求地址进行解析,还要进行各种判断,代码乱,不易阅读;再比如,实现静态资源访问功能,还要使用文件读取模块,对文件内容读取,还要设计响应内容类型,但实际和网站本身的业务逻辑没有关系;还有,接收post请求参数的代码,需要对请求对象添加事件,手动拼接请求参数,对请求参数的格式进行转化,都是复杂的,并且还是和和业务逻辑没有关系;原生JS实现网站应用比较困难,express就出现了

    2)这个是nodejs的第三方模块-使用 npm install express 命令进行下载。企业中创建web应用的标准

    1.2 Express框架特性

    提供了方便简洁的路由定义方式:router第三方模块 ,其实就是从express框架中抽取出来的对获取HTTP请求参数进行了简化处理:不用再转换格式,直接拿到对象类型模板引擎 支持程度高,方便渲染动态HTML页面;提供了中间件(对请求的拦截)机制有效控制HTTP请求拥有大量第三方中间件 对功能进行扩展:非常少的代码,做同样的事情

    1.3 原生Node.js与Express框架对比 之 路由

    app.on('request', (req, res) => {

         // 获取客户端的请求路径

         let { pathname } = url.parse(req.url);

         // 对请求路径进行判断 不同的路径地址响应不同的内容

         if (pathname == '/' || pathname == 'index') {

            res.end('欢迎来到首页');

         } else if (pathname == '/list') {

            res.end('欢迎来到列表页');

         } else if (pathname == '/about') {

            res.end('欢迎来到关于我们页面')

         } else {

            res.end('抱歉, 您访问的页面出游了');

         }

     });

    // 当客户端以get方式访问/

     app.get('/', (req, res) => {

         // 对客户端做出响应

         res.send('Hello Express');

     });

     // 当客户端以post方式访问/add路由时

     app.post('/add', (req, res) => {

        res.send('使用post方式请求了/add路由');

     });

     

    1.4 原生Node.js与Express框架对比 之 参数

    app.on('request', (req, res) => {

        // 获取GET参数

        let {query} = url.parse(req.url, true);

        // 获取POST参数

        let postData = '';

        req.on('data', (chunk) => {

            postData += chunk;

        });

        req.on('end', () => {

            console.log(querystring.parse(postData)

        }));

     });

    app.get('/', (req, res) => {

        // 获取GET参数req.query

        console.log(req.query);

     });

     app.post('/', (req, res) => {

        // 获取POST参数 req.body

        console.log(req.body);

     })

     

    1.5 Express初体验

    使用Express框架 创建web服务器及其简单,调用express模块 返回的函数即可

    命令行下载 npm install express

    //1, 引入Express框架,返回值是一个方法,通过调用这个方法,就可以创建网站服务器,就不用HTTP模块和调用createserver()方法

     const express = require('express');

    //2, 使用框架创建web服务器 + 监听端口 = 向外提供服务

     const app = express();

     

     // 4, 当客户端以get方式访问/路由时, 服务器要创建路由来响应客户端的请求;如何创建路由,和第三方模块 router是一样的 app.get(‘默认访问地址/’,请求处理函数,两个参数分别为 请求对象和 响应对象) 用来接受 get 请求

     app.get('/', (req, res) => {

    // 不再是res.end(), 对客户端做出响应 send()方法会根据内容的类型自动设置请求头

    // send() 内部回检测响应内容的类型;会自动设置HTTP状态码;会帮我们自动设置响应的内容类型以及 编码

        res.send('Hello Express'); // <h2>Hello Express</h2> {say: 'hello'}

     });

     

    //在定义一个路由,当访问 / list 的时候,响应一个其他内容;send 内部 还可以传递Json 对象

    app.get('/list', (req, res) => {

               res.send({name: '', age: 20})

    })

    //3, 程序监听3000端口

     app.listen(3000);

     

    2. 中间件

    2.1 什么是中间件

    1) 中间件就是 一堆方法可以 接收客户端发来的请求、可以对请求做出响应也可以将请求继续交给下一个中间件继续处理。专门接受请求处理请求的

    下图:中间件处理请求的过程:

    图两边是当客户端浏览器, 向中间的服务器发送请求

    当浏览器发送请求,服务器可以使用中间件 接受这个请求进行处理,直接对客户端做出响应,或者交给下一个中间件继续处理,有下一个 中间件对客户端浏览器做出相应;

    中间件好处:可以对复杂的请求处理逻辑,进行分开处理,也可以再请求到到指定路由之前做一些验证:比如查看用户是不是登录,如果登录,在向下继续执行

    2) 中间件主要由两部分构成,中间件方法以及请求处理函数。 中间件方法 由Express框架提供,负责拦截请求,请求处理函数 由开发人员提供,负责处理请求。

    app.get('请求路径', '处理函数')   // 接收并处理get请求

    app.post('请求路径', '处理函数')  // 接收并处理post请求

    3) 可以针对同一个请求设置 多个中间件,对同一个请求进行多次处理。

    默认情况下,请求从上到下依次匹配中间件,一旦匹配成功,终止匹配

    可以调用第三个参数next()方法将请求的控制权交给下一个中间件,直到遇到结束请求的中间件

    app.get('/request', (req, res, next) => {

         req.name = "zhangsan";

         next();

     });

    app.get('/request', (req, res) => {

         res.send(req.name);

     });

     

     

    2.2 app.use中间件用法

    -   app.use 匹配所有的请求方式可以直接传入请求处理函数,代表接收所有的请求,只要客户端发来请求,就可以匹配到当前中间件

    中间件是有顺序的,所以,中间件必须定义在其他前边;否则其他中间件匹配到了这个请求,有没有将权力交给下一个中间件,也是匹配不到这个中间件的

    app.use((req, res, next) => { console.log(req.url);  next(); });

    app.use 第一个参数 也可以传入请求地址,代表不论什么请求方式,只要是这个请求地址就接收这个请求。

    app.use('/admin', (req, res, next) => { console.log(req.url); next(); });

    2.3 中间件应用

    1. 路由保护,客户端在访问 需要登录的页面时,可以先使用中间件判断用户登录状态,用户如果未登录,则拦截请求,直接响应, 禁止用户进入需要登录的页面

    // 定义一个路由:要访问必须要先登录可以的

    2. 网站维护公告,在所有路由的最上面定义接收所有请求的中间件,直接为客户端做出响应,网站正在维护中。

    // 网站公告,比如在凌晨 6:00 -12:00 要维护,不想要用户访问这个网站,要定义在所有的路由的前边,没有调用 next(), 请求到这里就截止了

     app.use((req, res, next) => {

              res.send('当前网站正在维护,请在其他时间段访问...')

    })

    3. 自定义404页面,用户访问路径不存在时,同时用户访问的页面不存在,当所有用户访问的上边所有的路由不存在,才会响应给用户,所以定义在所有路由最后边,不会调用next();status404)更改状态码,为客户端响应404状态码以及提示信息

    2.4 错误处理中间件

    在程序执行的过程中,不可避免的会出现一些无法预料的错误,比如文件读取失败,数据库连接失败,错误处理中间件是一个集中处理错误的地方。

    想要出错以后,还能继续运行,需要捕获错误,加入错误处理;程序错误分为两种:

    应用逻辑错误:=bug 开发阶段解决读取硬盘文件/数据库连接错误:无法开发阶段预料到,在运行过程中,需要被捕获和妥善处理;

    如何处理错误呢?在每一个会出错的地方进行判断,但是代码太多!所以提供了错误处理中间件;

    只能捕获到 同步代码错误!!!,异步需要手动触发调用next(0方法 当异步程序出现错误时,调用next()方法,并且将错误信息通过参数的形式传递给next()方法,即可触发错误处理中间件

    有四个参数,发生错误,自动执行错误处理中间件

    app.use((err, req, res, next) => {

         res.status(500).send('服务器发生未知错误');

     })

    如果文件读取错误,系统会把错误信息通过参数传给我们,我们对错误对象进行判断,如果它真的时错误对象,不是null,就调用next()方法,传给他,他就会触发错误处理中间件了

    app.get("/", (req, res, next) => {

         fs.readFile("/file-does-not-exist", (err, data) => {

             if (err) {

                next(err);

             }

         });

    });

    //05js 错误处理中间件

    // 引入express框架 + 文件读取模块

    const express = require('express');

    const fs = require('fs');

    // 创建网站服务器

    const app = express();

    // 普通的路由中间件

    app.get('/index', (req, res, next) => {

           // throw new Error('程序发生了未知错误') 抛出错误 ,不报错往下执行

           fs.readFile('./01.js', 'utf8', (err, result) => {

                 if (err != null) {

                        next(err) // 传参数,代表触发中间件,不传参数,代表控制权交给下一个

                 }else {

                        res.send(result)

                 }

           })

           // res.send('程序正常执行')

    })

    // 错误处理中间

    app.use((err, req, res, next) => {

           res.status(500).send(err.message);

    })

    // 监听端口 

    app.listen(3000);

    console.log('网站服务器启动成功');

    2.5 捕获错误

    node.js,异步API的错误信息都是通过 回调函数 获取的支持Promise对象的异步API 发生错误可以通过catch方法捕获 异步函数执行如果发生错误要如何捕获错误呢

    try catch 可以捕获 异步函数以及其他同步代码 在执行过程中发生的错误,但是 不能捕获其他类型的API发生的错误

    app.get("/", async (req, res, next) => {

         // 如果程序没有错误,跳到trycatch外;如果程序有错误,会执行catch里边的代码,里边的参数就是错误信息,可以调用next方法,手动触发错误处理中间件;try()里边的代码,是从数据块中查询数据,如果查询失败,就跳转catch,执行并将错误信息传给错误处理中间件;

         try {

             await User.find({name: '张三'})

         }catch(ex) {

             next(ex); // 调用next() 触发错误处理中间件

         } });

    命令行已经不报错了,程序就可以继续执行;增加了我们程序的健壮性

     

    3. Express请求处理

    3.1 构建模块化路由

    虽然已经可以通过 app.get(), app.post()方法创建路由了,但是在一般情况下,路由的数量是非常多的,如果将所有的放在同一文件中,非常可怕,所以express提供了模块化,进行分类,不同的类型路由放在不同的模块中,方便管理。

    例如:博客网站:用户看的文章列表,详情页面;管理员看的文章发布,管理页面等。设置不同的路由进行分别管理

    const express = require('express') // 引入框架,返回express方法,直接调用或者使用他下边的其他方法;比如 express.Router用来创建路由

    const home = express.Router();// 创建路由对象

    app.use('/home', home); // 将路由和请求路径进行匹配;当客户端访问什么请求路径时/home'才能使用当前路由来处理,用app.use()方法来匹配 home;代码中并没有请求处理函数,请求来了以后,在哪里处理呢?具体请求处理再二级路由中完成

    home.get('/index', () => {// home路由下的get()方法继续创建路由,访问:/home/index 二级路由

             res.send('欢迎来到博客展示页面'); //  /home/index

     });

    3.2 构建模块化路由

    // home.js

    // admin,js

    // app.js

    3.3 GET参数的获取

    Express框架中使用 req.query 即可获取 GET参数, query 属性下存的就是 get请求参数,不在需要引入url 模块,通过对请求地址进行解析来获取get 请求参数了;框架内部会将GET参数 转换为 对象并返回

    // 接收地址栏中问号后面的参数,客户端访问时加了请求参数 name=zhangsan&age=30

    // 例如:  http://localhost:3000/?name=zhangsan&age=30

     app.get('/', (req, res) => {

        console.log(req.query); // 直接通过 req.query 就可以拿到?号后的请求参数了,并且已经解析成对象类型{"name": "zhangsan", "age": "30"} });

     

    3.4 POST参数的获取

    Express中接收 post请求参数 需要借助第三方包 body-parser。Npm i body-parser下载

    const bodyParser = require('body-parser'); // 引入body-parser模块

    app.use(bodyParser.urlencoded({ extended: false }));// 配置body-parser模块;使用app.use()这个中间件拦截所有请求,调用'body-parser'模块下边的 urlencoded() 方法,对请求进行处理,方法内部会检测当前请求中是不是包含请求参数,如果包含,就接受并转换为对象类型;然后在为req这个请求添加一个属性,属性的名字叫body;并且将参数作为值赋值给 req.body属性,最后调用next()将请求控制权交给下一个中间件

    app.post('/add', (req, res) => { // 接收请求

        console.log(req.body); // 接收post请求参数

     })

    10.js 如何获取post请求参数

     

     

     

    如何发送 post 请求,通过表单就可以:post.html

    点击提交后,就提交到 /add这个路由地址去了:

    11.js app.use方法

    3.5 Express 路由参数

    传递和接受 get 请求参数,还有另一种方式; 路由参数;可以让请求地址看起来美观,路由代码容易阅读;更容易看出传了那些参数;:id 是一个占位符,请求当前路由,要传递一个id 作为参数,不是实际的参数

    app.get('/find/:id', (req, res) => {

    console.log(req.params); // {id: 123} req.params 获取参数

     });

    localhost:3000/find/123  // 请求参数/id = 123

    3.6 静态资源的处理

    通过Express内置的 express.static可以方便地托管静态文件,例如img、CSS、JavaScript 文件等。

    app.use(express.static('public')); express.static(‘参数:静态资源存放的目录’);调用传给app.use()中间件,拦截所有请求,将请求交给express.static()这个方法处理,并且将静态资源目录告诉express.static()方法;方法内部判断客户端发来的请求,如果是静态资源请求,直接响应给客户端,终止请求;如果不是再方法内部调用next()将请求控制权交给下一个中间件开启静态资源访问功能后,就可以,public 目录下面的文件就可以通过以下方式访问了。

    http://localhost:3000/images/kitten.jpg  http://localhost:3000/css/style.css  http://localhost:3000/js/app.jshttp://localhost:3000/images/bg.png  http://localhost:3000/hello.html  

    访问:http://localhost:3000/static/images/1.jpg

     

    4. express-art-template模板引擎

    4.1 模板引擎

    为了使 art-template模板引擎 能够更好的和 Express框架配合,模板引擎官方在原art-template模板引擎的基础上封装了express-art-template。使用 npm install art-template express-art-template 命令进行安装。

    // 告诉express 框架,使用的模板引擎是什么? 当渲染后缀为art的模板时 使用express-art-template

     app.engine('art', require('express-art-template'));

      // 设置模板存放目录 app.setexpress框架进行配置

     app.set('views', path.join(__dirname, 'views'));

      // 渲染模板时不写后缀 默认拼接art后缀

     app.set('view engine', 'art');

     app.get('/', (req, res) => {

         // 渲染模板

         res.render('index');

     });

    4.2 app.locals 对象

    不同的页面中,总会有公共数据,代码中如何查询公共数据呢

    在不同页面路由中 都去查询这个相同的数据,render 将数据填充到模板中,麻烦; 一次,所有能用到都而已拿到这个数据呢?将变量设置到 app.locals 对象下面,这个数据在所有的模板中都可以获取到。!!!

    app.locals.users = [{

         name: '张三',

         age: 20

     },{

         name: '李四',

         age: 20

    }]

     

    Processed: 0.009, SQL: 9