阅读 105

express

重要的概念

简单的说web服务器要做的事情就是读取请求-->写入响应,根据http协议,请求的数据包括请求行、请求头(headers)和请求体,响应的数据包括响应行、响应头(headers)和响应,http复杂的地方在于headers的规则比较多。web框架的作用就是帮助我们更便捷高效地读取请求和设置响应

express最重要的概念就是中间件,核心的api为:app.use(),express应用到处都是中间件的使用。甚至可以说express就是一个中间件的库。 请求进来后经过一个个中间件函数的“加工”,在任何一个“加工”过程都可以完成响应,或者使用next()进入下一个中间件。

先看看官方的hello world示例:

const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
复制代码

你会发现为啥没有使用use中间件,不是说express到处都是use吗?其实这段代码相当于这样写:

const express = require('express')
const app = express()
const port = 3000
app.use((req, res) => {
    if(req.path === "/" && req.method === "GET") {
        res.send('Hello World!')
    }
})
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
复制代码

app.get()也只是一个语法糖,如果你没有发现express就是一个中间件的库,大概是因为里面基于app.use的语法糖太多了,例如app.post()、app.route()等等。其实express中基于路由的封装,本身就是在中间件的基础上加了一层请求路径的处理和判断。

另外很多基于express的库,只要是通过use调用的,都是返回一个中间件。例如express自带的express.static

app.use(express.static(path.join(__dirname, 'public')));
复制代码

express.static() 返回值或许可以长这样(纯粹瞎猜的):

(req, res, next) => {
    if(请求路径匹配) {
        // 读取文件并响应
    } else {
        next()
    }
}
复制代码

中间件的模式很方便往应用中加功能,也有利于的第三方开发者丰富express生态。

下面大概看一遍express的api文档并记录重要的知识点。

express

express.json()

将数据解析成json。例如解析application/json类型,它是json字符串,最终会被解析成json

express.urlencoded()

处理像application/x-www-form-urlencoded类型(该类型是以key=xxx&name=111的形式传输)的数据,解析成对象

express.raw()

把请求体解析为Buffer

express.text()

把请求体解析为字符串

总结: 上面的接口都是处理请求主体的数据,它会根据请求的content-type(或自定义)来决定是否处理。例如express.json()默认解析content-type为“application/json”的请求,如果content-type为“application/json”但是请求体是个普通字符串,这样就会解析出错。另外请求的数据是以流的形式传输,使用这类中间件就可以直接在request.body中得到需要的数据。否则就只能手动读取流数据,再进行解析。

express.static()

可以挂载静态资源。 注意点:如果访问文件不存在,则会转给后面的请求处理中间件:

const express = require('express')
const app = express()
app.use(express.static('static'))
app.use((request, response, next) => {
  response.end('hi')
  next()
})
app.listen(3000, () => console.log(`App listening on port 3000!`))
复制代码

上面代码访问文件不存在还是会返回hi,存在则返回文件。(又一次说到中间件了)

Application

  • app.set (可设置模板引擎 )

  • app.get (app.set设置的值)

  • app.locals 全局变量

  • app.use

  • app.post/app.put/app.get 等等

  • app.on('mount', ()=>{})

Request

大多数属性只是获取请求中直接能拿到的信息,只是express简单帮你加工判断一下,比如req.baseUrl、req.body、req.cookies、req.hostname、req.method、req.query等等。 需要注意几个:

  • req.fresh: 浏览器协商缓存有关, 根据请求头和响应头判断是否可以使用浏览器缓存,判断规则可参考这个
  • req.range: 和文件分片下载有关

Response

location 重定向配合301状态码

format 根据请求的accept来响应不同的数据

attachment 帮你设置Content-Disposition响应头,实现下载

send一次性发送 / write流的方式写

写的比较粗略,后面用到再慢慢补充吧

其它文章: