# 重写 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.baseUrlreq.originalUrl
  2. 定义为获取器(例如:req.securereq.ip

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

可以使用 Express API 扩展 API 覆盖类别 2 下的属性。

以下代码重写了如何导出 req.ip 的值。现在,它只返回 Client-IP 请求标头的值。

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

# 原型

为了提供 Express.js API,传递给 Express.js(例如通过 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)
Last Updated: 6/17/2023, 6:57:19 PM