第三方Express 路由和路由中间件

文章目录


1、Express 应用使用回调函数的参数: request 和 response 对象来处理请求和响应的数据。

  1. Request 对象
    request 对象表示 HTTP 请求,包含了请求查询字符串,参数,内容,HTTP 头部等属性

    属性/方法 说明
    app 当callback为外部文件时,用req.app访问express的实例
    baseUrl 获取路由当前安装的URL路径
    body/cookies 获得「请求主体」/ Cookies
    fresh/stale 判断请求是否还「新鲜」
    hostname/ip 获取主机名和IP地址
    originalUrl 获取原始请求URL
    params 获取路由的parameters
    path 获取请求路径
    protocol 获取协议类型
    query 获取URL的查询参数串
    route 获取当前匹配的路由
    subdomains 获取子域名
    accepts() 检查可接受的请求的文档类型
    acceptsCharsets/acceptsEncodings/acceptsLanguages 返回指定字符集的第一个可接受字符编码
    get() 获取指定的HTTP请求头
    is() 判断请求头Content-Type的MIME类型
  2. Response 对象
    response 对象表示 HTTP 响应,即在接收到请求时向客户端发送的 HTTP 响应数据

    属性/方法 说明
    app 当callback为外部文件时,用req.app访问express的实例
    append() 追加指定HTTP头
    set() 在res.append()后将重置之前设置的头
    res.cookie(name,value [,option]) 设置Cookie
    opition domain / expires / httpOnly / maxAge / path / secure / signed
    clearCookie() 清除Cookie
    download() 传送指定路径的文件
    get() 返回指定的HTTP头
    json() 传送JSON响应
    jsonp() 传送JSONP响应
    location() 只设置响应的Location HTTP头,不设置状态码或者close response
    redirect() 设置响应的Location HTTP头,并且设置状态码302
    render(view,[locals],callback) 渲染一个view,同时向callback传递渲染后的字符串,如果在渲染过程中有错误发生next(err)将会被自动调用。callback将会被传入一个可能发生的错误以及渲染后的页面,这样就不会自动输出了。
    send() 传送HTTP响应
    sendFile(path [,options] [,fn]) 传送指定路径的文件 -会自动根据文件extension设定Content-Type
    set() 设置HTTP头,传入object可以一次设置多个头
    status() 设置HTTP状态码
    type() 设置Content-Type的MIME类型

2、Express路由

路由是指应用程序的终端节点 (URI) 如何响应客户端请求。

在Express中,路由指的是客户端的请求与服务器处理函数之间的映射关系。

Express中的路由分3部分组成,分别是请求的类型、请求的URL地址、处理函数,格式如下:app.method(path, handler)

1.路由方法

javascript 复制代码
// GET method route
app.get('/', function (req, res) {
  res.send('GET request')
})

// POST method route
app.post('/', function (req, res) {
  res.send('POST request')
})

app.all() 用于在所有 HTTP 请求方法的路径上加载中间件函数。

无论是使用 GET、POST、PUT、DELETE 还是 http 模块中支持的任何其他 HTTP 请求方法,都会对路由 "/secret" 的请求执行以下处理程序。

javascript 复制代码
app.all('/secret', function (req, res, next) {
  console.log('all')
  next() // pass control to the next handler
})

2.路由路径

路由路径可以是字符串、字符串模式或正则表达式。

javascript 复制代码
// acd和abcd
app.get('/ab?cd', function (req, res) {
  res.send('ab?cd')
})




总结:问号前面字符可有可无

javascript 复制代码
app.get('/ab(cd)?e', function (req, res) {
  res.send('ab(cd)?e')
})



总结:问号前面括号内的字符可有可无

javascript 复制代码
app.get('/ab+cd', function (req, res) {
  res.send('ab+cd')
})





总结:加号前面字符可无限叠加

javascript 复制代码
app.get('/ab*cd', function (req, res) {
  res.send('ab*cd')
})



总结:星号前面的字符为开始,后边的字符为结束字符,中间可以任意字符或数字

javascript 复制代码
app.get(/a/, function (req, res) {
  res.send('/a/')
})


总结:满足正则/a/的都满足此方法

javascript 复制代码
app.get(/.*fly$/, function (req, res) {
  res.send('/.*fly$/')
})


总结:满足正则/.*fly$/以fly字符结束的路由

3.路由处理程序

在没有理由继续当前路由时将控制权传递给后续路由。next('route')

路由处理程序可以采用函数、函数数组或两者的组合形式。

  1. 单个回调函数可以处理路由。

    javascript 复制代码
    var express = require('express');
    var app = express();
    app.get('/abc', function (req, res) {
      res.send('hello abc');
    })
    app.listen(8081, function () {
      console.log("服务启动")
    })
  2. 多个回调函数可以处理一个路由(确保指定对象)next();

    javascript 复制代码
    var express = require('express');
    var app = express();
    app.get('/abc', function (req, res, next) {
      console.log(111)
      next()
    }, function(req, res) {
      res.send('hello abc next');
    })
    app.listen(8081, function () {
      console.log("服务启动")
    })	


  3. 回调函数数组可以处理路由。

    javascript 复制代码
    var express = require('express');
    var app = express();
    var a0 = function (req, res, next) {
      console.log('A0')
      next()
    }
    var a1 = function (req, res, next) {
      console.log('A1')
      next()
    }
    var a2 = function (req, res) {
      res.send('Hello from A!')
    }
    app.get('/abc', [a0, a1, a2])
    app.listen(8081, function () {
      console.log("服务启动")
    })


  4. 独立函数和函数数组的组合可以处理路由。

    javascript 复制代码
    var express = require('express');
    var app = express();
    var a1 = function (req, res, next) {
      console.log('A1')
      next()
    }
    var a2 = function (req, res) {
      res.send('Hello from A!')
    }
    app.get('/abc', function (req, res, next) {
      console.log('A0')
      next()
    },[a1, a2])
    app.listen(8081, function () {
      console.log("服务启动")
    })


3. 模块化路由

为了方便对路由进行模块化的管理,Express不建议将路由直接挂载到app上,而是推荐将路由抽离为单独的模块。

将路由抽离为单独模块的步骤如下:

1.创建路由模块对应的.js文件

2.调用express.Router()函数创建路由对象

3.向路由对象上挂载具体的路由

4.使用module.exports向外共享路由对象

5.使用app.use()函数注册路由模块

  1. 创建路由模块

    javascript 复制代码
    // router.js   文件
    var express = require('express'); // 1.导入express
    var router = express.Router();    // 2.创建路由对象
     
    router.get('/login/info', (req, res) => {   // 3.挂载登录用户信息
        res.send('Get user list.');
    });
    router.post('/singUp/add', (req, res) => {   // 4.挂载注册用户的路由
        res.send('Add new user.');
    });
    module.exports = router;  // 5.向外导出路由对象
  2. 注册路由模块

    javascript 复制代码
    const express = require('express');
    const app = express();
    // 1.导入路由模块
    const userRouter = require('./router.js');
    // 2.使用app.use()注册路由模块
    app.use(userRouter);
    app.listen(8081, () => {
        console.log('http://127.0.0.1')
    })
  3. 为路由模块添加前缀

    javascript 复制代码
    // 类似于托管静态资源时,为静态资源统一挂载访问前缀一样
    // 1.导入路由模块
    const userRouter = require('./router.js');
    // 2.使用app.use()注册路由模块,并添加统一的范围前缀 /api 
    app.use('/api', userRouter);

4. Express中间件

1.中间件简介

  1. 中间件简介
    中间件是一种特殊的路由处理函数,它可以在请求到达目标处理函数之前,进行一些预处理操作。Express 支持使用中间件来实现各种功能,例如身份验证、请求日志记录,处理 CORS(跨源资源共享)等。
    注意:中间件函数的形参列表中,必须包含next参数,而路由处理函数中只包含req和res。
    next函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由。
    可以使用app.use()连续定义多个全局中间件。客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用

    javascript 复制代码
    const express = require('express');
    const app = express();
    // 一个简单的中间件
    app.use((req, res, next) => {
      console.log(`Request received at ${new Date()}`);
      next(); // 将控制权传递给下一个中间件或路由处理器
    });
    // 一个路由处理器,用于处理 GET 请求
    app.get('/', (req, res) => {
      res.send('Hello, World!');
    });
    
    // 启动服务器
    app.listen(8081, () => {
      console.log('Server is running on port 8081');
    });
  2. 局部中间件
    不使用app.use()定义的中间件,叫做局部生效的中间件, 中间件只在"当前路由中生效",

    javascript 复制代码
    var express = require('express');
    var app = express();
    
    var myLogger = function (req, res, next) {
      console.log('LOGGED')
      next()
    }
    app.get('/', myLogger, function (req, res) {
      res.send('Hello World!')
    })
  3. 中间件的5个使用注意事项

    • 一定要在路由之前注册中间件
    • 客户端发送过来的请求,可以连续调用多个中间件进行处理
    • 执行完中间件的业务代码之后,不要忘记调用next()函数
    • 为了防止代码逻辑混乱,调用next()函数后不要再写额外的代码
    • 连续调用多个中间件时,多个中间件之间,共享req和res对象
  4. 监听 req 的 data 事件
    在中间件中,需要监听req对象的data事件,来获取客户端发送到服务器的数据。
    如果数据量比较大,无法一次性发送完毕,则客户端会把数据切割后,分批发送到服务器。所以data事件可能会触发多次,每一次触发data事件时,获取到数据只是完整数据的一部分,需要手动对接收到的数据进行拼接。

    javascript 复制代码
    // 定义变量,用来储存客户端发送过来的请求体数据
    let str = ''
    // 监听 req 对象的 data 事件(客户端发送过来的新的请求体数据)
    req.on('data',(data) => {
      // 打印请求数据
      console.log(data)
    })
  5. 监听 req 的 end 事件
    当请求体数据接收完毕之后,会自动触发req的end 事件。
    可以在req的end 事件中,拿到并处理完整的请求体数据。

    javascript 复制代码
    // 监听 req 对象的 end 事件(请求体发送完毕后自动触发)
    req.on('end',() => {
      // => 打印完整的请求体数据
      console.log(str)
      // TODO: 业务逻辑
      // .......
    })

2.中间件分类

  1. 应用程序级中间件
    通过app.use()或app.get()或 app.post(),绑定到app实例上的中间件,叫做应用级别的中间件,

    javascript 复制代码
    var app = express();
    var myLogger = function (req, res, next) {
      console.log('LOGGED')
      next()
    }
    // 应用级别的中间件(全局中间件)
    app.use((req, res, next) => {
      req.name = 'router'
      req.on('end',() => {
        console.log('end')
      })
      next();
    });
    // 应用级别的中间件(局部中间件)
    app.get('/', myLogger, (req, res) => {
      console.log(req.name)
      res.send('Home page.')
    });
    app.listen(8081, function () {
      console.log("服务启动")
    })
  2. 路由器级中间件
    绑定到express.Router()实例上的中间件,叫做路由级别的中间件。它的用法和应用级别中间件没有任何区别。只不过,应用级别中间件是绑定到 app实例上,路由级别中绚件摸定到router 实例上

    javascript 复制代码
    var express = require('express')
    var app = express()
    var router = express.Router()
    router.use(function (req, res, next) {
      console.log('Time:', Date.now());
      next()
    })
    app.use('/', router)
    app.listen(8081, function () {
      console.log("服务启动")
    })
  3. 错误处理中间件
    错误处理中间件是专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题。
    格式:错误级别的中间件的 function 处理函数中,必须有 4 个形参,形参顺序从前到后,分别是(err,req,res,next)。
    注意:错误级别的中间件,必须注册在所有路由之后

    javascript 复制代码
    app.get('/', (req, res) => { // 1.路由
        throw new Error('服务器内部发生了错误');  // 1.1.抛出一个自定义的错误
        res.send('Home Page.');
    });
    app.use((err, req, res, next) => {    // 2.错误级别的中间件
        console.log('发生了错误:' + err.message);   // 2.1.在服务器打印错误消息
        res.send('Erroe!' + err.message); // 2.2.向客户端响应错误相关的内容
    });
  4. 内置中间件
    三个内置的中间件分别是
    express.static 是快速托管静态资源的内置中间件 例如:HTML文件、图片、CSS样式等(无兼容性)
    express.json是拿来解析json格式数据的
    express.urlencoded是拿来解析urlencoded格式数据的

    javascript 复制代码
    var express = require('express');
    var app = express();
    // 注意这是中间件 所以必须配置到路由之前
    app.use(express.json())
    app.use(express.urlencoded({extended : false}))
    app.listen(8081, function () {
      console.log("服务启动")
    })
  5. 第三方中间件
    非Express官方内置的,而是由第三方开发出来的中间件,叫做第三方中间件。在项目中,大家可以按需下载并配置第三方中间件,从而提高项目的开发效率。
    安装所需功能的 Node.js 模块,然后在应用程序级别或路由器级别将其加载到应用程序中。
    以cookie-parser为示例:

    javascript 复制代码
    $ npm install cookie-parser
    javascript 复制代码
    var express = require('express')
    var app = express()
    var cookieParser = require('cookie-parser')
    app.use(cookieParser())

3.自定义中间件

自定义中间件步骤:

  1. 定义中间件

  2. 监听req的data事件

  3. 监听req的end事件

  4. 使用querystring模块解析请求体数据

  5. 将解析出来的数据对象挂载为req.body

  6. 将自定义中间件封装为模块

    javascript 复制代码
    // myparse.js
    //1.1 导入内置模块
    const qs=require('querystring')
    //1.2 编写解析函数
    function myparse(req,res,next){
        //2.2 定义一个变量存储客户端字符串
        let str=''
     
        //2.1 对客户端请求数据的监听
        //注意是对客户端对象进行监听,而不是服务器
        req.on('data',(chunk)=>{
            str+=chunk
        })
     
        //2.4 进行发送数据结束的监听
        req.on('end',()=>{
            //倘若有响应,说明数据发送结束,我们已经拿到所有数据
            console.log(str)
            //4.2 利用内置模块的parser()进行数据解析
            const body=qs.parse(str)
            //4.3 进行数据对象的挂载
            req.body=body
            console.log(body)
        })
    
        //2.5 不要忘记需要调用next函数
        next()
    }
    //1.4 通过module.exports暴露
    module.exports = myparse
    javascript 复制代码
    // 使用
    var express = require('express');
    var app = express();
    // 2.1 导入自定义解析模块
    const myparse = require('./mybody-parse')
    app.use(myparse)
    app.get('/login', function (req, res) {
      console.log(req.body);
      res.end(req.body);
    })
相关推荐
腾讯TNTWeb前端团队6 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰10 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪10 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪10 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy11 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom11 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom11 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom11 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom12 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom12 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试