重写 Express API

Express API 由请求和响应对象上的各种方法和属性组成。它们通过原型继承。Express API 有两个扩展点:

  1. express.requestexpress.response 处的全局原型。
  2. app.requestapp.response 处的应用特定原型。

更改全局原型将影响同一进程中所有加载的 Express 应用。如果需要,可以通过在创建新应用后仅更改应用特定原型,使更改仅限于特定应用。

方法

您可以通过分配自定义函数,用自己的实现覆盖现有方法的签名和行为。

以下是覆盖 res.sendStatus 行为的示例。

app.response.sendStatus = function (statusCode, type, message) {
  // code is intentionally kept simple for demonstration purpose
  return this.contentType(type)
    .status(statusCode)
    .send(message)
}

上述实现完全改变了 res.sendStatus 的原始签名。它现在接受状态码、编码类型以及要发送给客户端的消息。

现在可以这样使用被覆盖的方法:

res.sendStatus(404, 'application/json', '{"error":"resource not found"}')

属性

Express API 中的属性要么是:

  1. 赋值属性(例如:req.baseUrl, req.originalUrl
  2. 定义为 getter(例如:req.secure, req.ip

由于第 1 类属性是在当前请求-响应周期的上下文中动态分配到 requestresponse 对象上的,因此它们的行为无法被覆盖。

第 2 类属性可以使用 Express API 扩展 API 进行覆盖。

以下代码重写了 req.ip 值的获取方式。现在,它只返回 Client-IP 请求头的值。

Object.defineProperty(app.request, 'ip', {
  configurable: true,
  enumerable: true,
  get () { return this.get('Client-IP') }
})

原型

为了提供 Express API,传递给 Express 的请求/响应对象(例如通过 app(req, res))需要继承自相同的原型链。默认情况下,请求是 http.IncomingRequest.prototype,响应是 http.ServerResponse.prototype

除非必要,建议仅在应用级别进行此操作,而非全局。同时,请注意所使用的原型应尽可能与默认原型在功能上保持一致。

// Use FakeRequest and FakeResponse in place of http.IncomingRequest and http.ServerResponse
// for the given app reference
Object.setPrototypeOf(Object.getPrototypeOf(app.request), FakeRequest.prototype)
Object.setPrototypeOf(Object.getPrototypeOf(app.response), FakeResponse.prototype)
编辑此页面