• 08_Express框架


    使用Node.js进行服务器开发,开发效率比较低,例如在实现路由功能和静态源访问功能时,代码写起来很烦琐
    为了提高Node.js服务器的开发效率,人们开发了Express框架,它可以帮助开发人员快速创建网站应用程序。

    1 初识Express

    1.1 Express简介

    Express是目前流行的基于Node.js运行环境的Web应用程序开发框架,它简洁且灵活,为Web应用程序提供了强大的功能。
    Express提供了一个轻量级模块,类似于jQuery(封装的工具库),它把Node.js的HTTP模块的功能封装在一个简单易用的接口中,用于扩展HTTP模块的功能,能够轻松地处理服务器的路由、响应、Cookie和HTTP请求的状态。

    Express的优势
    • 简洁的路由定义方式。
    • 简化HTTP请求参数的处理。
    • 提供中间件机制控制HTTP请求。
    • 拥有大量第三方中间件。
    • 支持多种模版引擎。

    1.2 Express安装

    使用npm包管理工具安装Express。
    npm init -y
    npm install express --save
    安装完成后,在当前目录下打开命令行工具执行“npm list express”命令,查看Express版本。

    1.3 搭建Web服务器

    基本步骤:

    • 引入express模块;
    • 调用express()方法创建服务器对象app;
    • 调用get()方法定义GET路由;
    • 调用listen()方法监听端口。
    // 引入express模块
    const express = require('express');
    // 创建Web服务器对象
    const app = express();
    // 定义GET路由
    app.get('/', (req, res) => { 
        // 对客户端做出响应,send()方法会根据内容的类型自动设置请求头
        res.send('Hello Express');
    }); 
    // 监听3000端口
    app.listen(3000);
    console.log('服务器启动成功');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2 Express中间件

    2.1 中间件简介

    Express通过中间件接收客户端发来的请求,并对请求做出响应,也可以将请求交给下一个中间件继续处理。
    中间件(Middleware)是指业务流程的中间处理环节。可以把中间件理解为处理客户端请求的一系列方法。
    如果把请求比作水流,那么中间件就是阀门,阀门可以控制水流是否继续向下流动,也可以在当前阀门处对水流进行排污处理,处理完成后再继续向下流动。
    图片1.png
    中间件机制可以实现哪些应用?

    • 路由保护:当客户端访问登录页面时,可以先使用中间件判断用户的登录状态,如果用户未登录,则拦截请求,直接响应提示信息,并禁止用户跳转到登录页面。
    • 网站维护:在所有路由的最上面定义接收所有请求的中间件,直接为客户端做出响应,并提示网站正在维护中。
    • 自定义404页面:在所有路由的最上面定义接收所有请求的中间件,直接为客户端做出响应,并提示404页面错误信息。

    2.2 定义中间件

    中间件主要由中间件方法请求处理函数这两个部分构成。
    中间件方法由 Express 提供,负责拦截请求。
    请求处理函数由开发人员编写,负责处理请求。
    常用的中间件方法有app.get()、app.post()、app.use(),其基本语法形式如下。

    app.get('请求路径', '请求处理函数');  // 接收并处理GET 请求
    app.post('请求路径', '请求处理函数'); // 接收并处理POST 请求
    app.use('请求路径', '请求处理函数'); // 接收并处理所有请求
    
    • 1
    • 2
    • 3
    app.get()中间件

    当客户端向服务器端发送GET请求时,app.get()中间件方法会拦截GET请求,并通过app.get()中间件中的请求处理函数对GET请求进行处理。

    app.get('/', (req, res, next) => {
        next();
    });
    
    • 1
    • 2
    • 3

    同一个请求路径可以设置多个中间件,表示对同一个路径的请求进行多次处理,默认情况下Express会从上到下依次匹配中间件。

    const express = require('express');
    const app = express();
    // 定义中间件
    app.get('/request', (req, res, next) => {
        req.name = '张三';
        next();
    });
    app.get('/request', (req, res) => {
        res.send(req.name);
    });
    app.listen(3000);
    console.log('服务器启动成功');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    app.post()中间件

    当浏览器向服务器发送POST请求时,app.post()定义的中间件会接收并处理POST请求。

    const express = require('express');
    const app = express();
    // 定义中间件
    app.post('/post', (req, res, next) => {
        req.name = '李四';
        next();
    });
    app.post('/post', (req, res) => {
        res.send(req.name);
    });
    app.listen(3000);
    console.log('服务器启动成功');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    app.use()中间件

    通过app.use()定义的中间件既可以处理GET请求又可以处理POST请求。在多个app.use()设置了相同请求路径的情况下,服务器都会接收请求并进行处理。

    const express = require('express');
    const app = express();
    app.use('/form', (req, res, next) => { 
        req.name = '张三';
        next();
    });
    app.use('/form', (req, res) => {
        res.send(req.name);
    });
    app.listen(3000);
    console.log('服务器启动成功');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    app.use()方法的请求路径参数可以省略,省略时表示不指定路径,所有的请求都会被处理。

    const express = require('express');
    const app = express();
    // 定义中间件,省略请求路径
    app.use((req, res, next) => {
        req.user = {};
        next();
    });
    // 添加post请求
    app.post('/post', (req, res, next) => {
        req.user.age = '30';
        next();
    });
    app.post('/post', (req, res) => {
        res.send(req.user.age);
    });
    // 添加get请求
    app.get('/request', (req, res, next) => {
        req.user.name = '张三';
        next();
    });
    app.get('/request', (req, res) => {
        res.send(req.user.name);
    });
    app.listen(3000);
    console.log('服务器启动成功');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    app.use()接收函数调用
    在上述使用app.use()时已知道app.use()可以接收请求处理函数。
    如果将请求处理函数作为函数的返回值传给app.use(),那么该返回值也可以被app.use()接收,这就是app.use()接收函数调用的语法。

    app.use(fn());
    function fn(obj) {
        return function(req, res, next) {
            next();
        };
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    const express = require('express');
    const app = express();
    // 在调用fn()函数时传入参数
    app.use(fn({ a: 1 }));
    function fn(obj) {
        return function (req, res, next) {
            // 根据obj.a的值打印不同的信息 
            if (obj.a === 1) {
                console.log(req.url)
            } else {
                console.log(req.method)
            };
            next();
        };
        
    };
    // 使用app.get()中间件定义“/fn”路由
    app.get('/fn', (req, res) => {
        res.send('ok');
    });
    app.listen(3000);
    console.log('服务器启动成功');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.3 中间件处理静态资源

    express.static()Express框架提供的内置中间件,它接收静态资源访问目录作为参数。
    使用express.static()内置中间件可以方便地托管静态文件。常用的静态资源有图片、CSS、JavaScript和HTML文件等。
    express.static()需要作为app.use()的参数使用。

    app.use(express.static('public'));
    
    • 1
    const express = require('express');
    const app = express();
    // 静态资源处理
    app.use(express.static('public'));
    app.listen(3000);
    console.log('服务器启动成功');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.4 中间件处理错误

    在程序执行的过程中,不可避免的会出现一些无法预料的错误,比如文件读取失败、数据库连接失败等。
    这时候就需要用到错误处理中间件了,用它来集中处理错误。
    利用app.use()定义错误处理中间件。

    app.use((err, req, res, next) => {
        console.log(err.message);
    });
    
    • 1
    • 2
    • 3
    const express = require('express');
    const fs = require('fs');
    const app = express();
    app.get('/readFile', (req, res, next) => { 
        fs.readFile('./a.txt', 'utf8', (err, result) => { 
            if (err != null) { 
                next(err); 
            } else {
                res.send(result)
            };
        });
    });
    // 错误处理中间件
    app.use((err, req, res, next) => { 
        res.status(500).send(err.message);
    });
    app.listen(3000);
    console.log('服务器启动成功');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2.5 中间件捕获异步函数错误

    异步函数错误是异步函数中以及其他同步代码在执行过程中发生的错误。使用try…catch…语法结合async、await关键字来捕获异步错误。

    app.get('/async', async (req, res, next) => {
        try {
            // readFile()是异步函数
            await readFile('./aaa.js');
        } catch(err) {
            next(err);
        };
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    const express = require('express');
    const fs = require('fs');
    const promisify = require('util').promisify;
    const readFile = promisify(fs.readFile);
    const app = express();
    // 未添加错误处理
    app.get('/async', async (req, res, next) => { 
        await readFile('./aaa.js');
    });
    // 添加错误处理
    app.get('/async', async (req, res, next) => {
        try {
            await readFile('./aaa.js');
        } catch(err) {
            next(err);
        };
    });
    app.listen(3000);
    console.log('服务器启动成功');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    3 Express模块化路由

    可以使用app.get()方法和app.post()方法来实现简单的路由功能,但没有对路由进行模块化管理。
    在实际的项目开发中,不推荐将不同功能的路由都混在一起存放在一个文件中,因为随着路由的种类越来越多,管理起来会非常麻烦。
    为了方便路由的管理,建议通过express.Router()实现模块化路由管理。

    3.1 模块化路由的基本使用

    express.Router()方法用于创建路由对象route,然后使用route.get()route.post()来注册当前模块路由对象下的二级路由,这就是一个简单的模块化路由。

    const route = express.Router();
    
    • 1

    route对象下可以定义二级路由。

    route.get('请求路径', '请求处理函数');   // 接收并处理 route 下的 GET 请求
    route.post('请求路径', '请求处理函数');  // 接收并处理 route 下的 POST 请求
    
    • 1
    • 2

    route对象创建成功后,使用app.use()注册route模块化路由。

    app.use('请求路径', route);
    
    • 1
    const express = require('express');
    const app = express();
    const route = express.Router();
    // 在route路由下创建二级路由
    route.get('/index', (req, res) => { 
        res.send('欢迎来到首页');
    });
    app.use('/route', route);
    app.listen(3000);
    console.log('服务器启动成功');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3.2 构建模块化路由

    express.Router()方法可以将同一类路由放在一个单独的文件中,每个单独的文件表示一个单独的模块,通过文件的名称来区分路由的功能。

    // home.js “博客前台”模块化路由
    const express = require('express');
    const home = express.Router();
    // 在home模块化路由下创建路由
    home.get('/index', (req, res) => { 
        res.send('欢迎来到博客展示页面');
    });
    module.exports = home;
    //admin.js “博客后台”的模块化路由
    const express = require('express');
    const admin = express.Router(); 
    // 在admin模块化路由下创建路由
    admin.get('/index', (req, res) => { 
        res.send('欢迎来到博客管理页面');
    }); 
    module.exports = admin;
    
    // module.js
    const express = require('express');
    const home = require('./route/home.js');
    const admin = require('./route/admin.js');
    const app = express();
    app.use('/home', home);
    app.use('/admin', admin);
    app.listen(3000);
    console.log('服务器启动成功');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    4 Express接收请求参数

    使用原生Node.js处理GET和POST请求参数是非常麻烦的,例如,为了获取GET请求参数,需要使用url模块对请求地址进行解析。
    为了降低开发的难度,Express通过req.queryreq.body和第三方模块body-parser对请求参数进行了处理。

    4.1 Express接收GET请求参数

    Express框架中的req.query用于获取GET请求参数,框架内部会将GET参数转换为对象并返回。

    app.get('/', (req, res) => {
        res.send(req.query);
    });
    
    • 1
    • 2
    • 3
    const express = require('express');
    const app = express();
    app.get('/query', (req, res) => {
        res.send(req.query);
    });
    app.listen(3000);
    console.log('服务器启动成功');
    // http://localhost:3000/query?name=zhangsan&age=30
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    使用表单发起GET请求,请求参数会被自动添加到请求地址后面,在服务器端使用req.query来获取请求参数。

    4.2 Express接收POST请求参数

    Express中的req.body用于获取POST请求参数,需要借助第三方body-parser模块将POST参数转换为对象形式。

    app.post('/body', (req, res) => { 
        res.send(req.body);
    });
    
    • 1
    • 2
    • 3

    body-parser是一个解析HTTP请求体的模块,使用这个模块可以处理POST请求参数,使用起来非常方便。

    app.use(bodyParser.urlencoded({ extended: false }));
    // { extended: false} 表示在方法的内部使用 querystring 系统模块来处理POST请求参数; 
    // { extended: true}  表示使用qs第三方模块进行处理。
    
    • 1
    • 2
    • 3

    在处理POST请求参数之前,首先要完成body-parser模块的安装。
    npm install body-parser@1.18.3 --save

    const express = require('express');
    const bodyParser = require('body-parser');
    const app = express();
    app.use(bodyParser.urlencoded({ extended: false }));
    app.post('/body', (req, res) => { 
        res.send(req.body);
    });
    app.listen(3000);
    console.log('服务器启动成功');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4.3 Express接收路由参数

    在定义路由时,可以在请求路径中传递参数,例如请求路径“/find/:id”中的“:id”是一个参数占位符,当浏览器向“/find/:id”地址发送请求时,“:id”对应的值就是参数值。
    通常情况下,把写在路由请求路径中的参数称为路由参数。
    通过请求路径传递参数,可以让路由代码看起来非常美观,且请求参数会被清晰地展示出来。

    app.get('/find/:id', (req, res) => {
        res.send(req.params);
    });
    
    • 1
    • 2
    • 3
    const express = require('express');
    const app = express();
    app.get('/find/:id', (req, res) => { 
        res.send(req.params);
    }); 
    app.listen(3000);
    console.log('服务器启动成功');
    // http://localhost:3000/find/123
    
    // 多个参数的传递
    app.get('/find/:id/:name/:age', (req, res) => { 
        res.send(req.params);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    5 Express模板引擎

    5.1 配置模板引擎

    为了使art-template模板引擎能够与Express框架配合使用,art-template模板引擎作者在原有的art-template模板引擎的基础上封装了express-art-template模板引擎。

    安装模板引擎

    npm install art-template express-art-template --save

    配置模板引擎
    const express = require('express');
    const path = require('path');
    const app = express();
    // 配置模板引擎
    app.engine('art', require('express-art-template'));
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'art'); 
    app.listen(3000);
    console.log('服务器启动成功');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5.2 模板引擎的简单使用

    成功配置express-art-template模板引擎后,就可以在Express框架中使用模板引擎了。

    
    {{ msg }}
    
    • 1
    • 2
    app.get('/art', (req, res) => { 
        // 渲染模板 
        res.render('index', {msg: 'message'}); 
    });
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    elasticsearch的安装及使用
    软件架构风格-BS三层架构
    Redis(二) Java操作Redis
    不能乱动的依赖包glibc,openssl,libcom_err
    学习 Python 编程的 11 个受用终身的技巧
    注意力机制 - 注意力提示
    calcite 初试-使用sql读取csv文件
    如何在排除子目录时挂载 Docker 卷
    linux运维基础一(shell两类命令&Hash缓存表&命令行历史)
    刷爆指针笔试题
  • 原文地址:https://blog.csdn.net/zhangchen124/article/details/133744161