花 15 分钟把 Express.js 搞明白,全栈没有那么难( 二 )

在 Postman 中请求地址 “http://localhost:9000/first/8?tag=test” 并传入请求体参数 {data: "xxx"},请求结果如下:

花 15 分钟把 Express.js 搞明白,全栈没有那么难

文章插图
对照请求参数和返回结果 , 可以发现路由地址中的 :id 占位符解析后被放到 “req.params” 对象下 。地址参数 ?tag=test 解析后被放到 “req.query” 对象下 。
但是有一个问题:请求体没有被解析出来 。
这是因为请求体是按照流处理的,无法直接获取到 , 我们需要一个第三方工具包协助 。首先安装如下:
$ yarn add body-parser然后在 index.js 中引入并加载:
const bodyParser = require('body-parser')app.use(bodyParser.json())现在重新请求 , 接可以看到 req.body 的返回结果了:
花 15 分钟把 Express.js 搞明白,全栈没有那么难

文章插图
响应对象路由处理函数的第二个参数表示响应对象,用于向客户端返回结果,也就是定义接口的返回值 。路由处理函数中必须设置响应,否则客户端请求会一直处于挂起状态,无返回值 。
常用的响应方法有以下三种 , 用于返回不同类型的数据:
  • res.json():发送 JSON 响应 。
  • res.render():发送视图响应(html) 。
  • res.send():发送各种类型的响应 。
我们统一使用 res.send() 方法响应数据 。一般在响应前还可以通过 res.status() 方法设置 HTTP 状态码 , 示例如下:
res.send('哈哈') // 状态码:200,返回值:"哈哈"res.status(201).send({msg: 'created',}) // 状态码:201,返回值:{msg:"created"}res.status(401).send('请登录') // 状态码:401,返回值:"请登录"发送响应时也常常会遇到问题,以下两条原则请牢记,避免踩坑:
  • 一个路由处理函数中只能响应一次,不能重复响应 。
  • res.send() 不能直接返回数字 。
分组路由使用 app 实例注册路由固然方便,但是如果定义的路由很多 , 都注册在 app 实例下很可能会带来全局污染,这与全局变量一个道理 。为了应用的健壮性,我们应该将路由分组 。
Express 提供了 Router 类来创建模块化的路由程序,它像一个微应用,可以随时被 app 实例挂载 。这样就可以把一组路由保存在一个单独的文件中,需要时加载 , 从而实现路由分组 。
创建一个 router 文件夹用于保存路由文件,然后创建 router/test.js 文件,在文件中呢写入路由代码 , 如下:
// router/test.jsvar express = require('express')var router = express.Router()router.post('/info', (req, res) => {res.send('TEST 路由组')})module.exports = router这样一个基本的路由模块就写好了,如果让其生效,需要在主程序中加载该模块:
const testRouter = require('./router/test.js')app.use('/test', testRouter)上述代码表示请求 “/test” 时加载路由模块 , 访问某个路由时使用该路径拼接路由地址,像下面这样:
http://localhost:9000/test/info# 返回 "TEST 路由组"为了开发规范,我们统一把路由定义为路由模块,而不直接在 app 下注册 。
理解中间件,搞懂框架原理Express 应用是由一系列中间件构成的 。中间件同样是一个听着很玄乎的词儿,但它的本质就是一个函数 。我们看一个中间件函数的代码示例:
var myLogger = function (req, res, next) {console.log('LOGGED')next()}中间件与普通函数的区别就是它有三个参数,分别表示请求对象(req),响应对象(res)和一个 next() 函数 ——— 也许你发现了,路由处理函数也是这个结构 。
没错,路由处理函数本身就是一个中间件 。
将中间件挂载到应用上,使用 app.use() 方法:
app.use(myLogger)看到这里你又会发现,请求体解析包 body-parser 也是这么挂载的 , 因为该包也是一个中间件 。
直接用 app.use() 挂载的中间件在收到任意请求时都会执行 。如果要限定执行条件,可以添加一个路径匹配,如下:
app.use('/test/*', myLogger)这样,只有以 /test 开头的请求才会执行 myLogger 中间件,这看起来与路由注册很相似 。其实注册路由正是这种中间件挂载方式的快捷写法 , 只不过多了一个请求方法的限制 。


推荐阅读