Skip to content

HTTP 上下文

每个 HTTP 请求都会生成一个新的 HTTP Context 类实例,并传递给路由处理程序、中间件和异常处理程序。

HTTP 上下文包含你可能需要的与 HTTP 请求相关的所有信息。例如:

  • 你可以使用 ctx.request 属性访问请求体、headers 和查询参数。
  • 你可以使用 ctx.response 属性响应 HTTP 请求。
  • 使用 ctx.auth 属性访问已登录用户。
  • 使用 ctx.bouncer 属性授权用户操作。
  • 等等。

简而言之,上下文是一个特定于请求的存储,保存正在进行的请求的所有信息。

获取 HTTP 上下文访问权限

HTTP 上下文通过引用传递给路由处理程序、中间件和异常处理程序,你可以按如下方式访问它。

路由处理程序

路由处理程序接收 HTTP 上下文作为第一个参数。

ts
import router from '@adonisjs/core/services/router'

router.get('/', (ctx) => {
  console.log(ctx.inspect())
})
ts
// title: 解构属性
import router from '@adonisjs/core/services/router'

router.get('/', ({ request, response }) => {
  console.log(request.url())
  console.log(request.headers())
  console.log(request.qs())
  console.log(request.body())
  
  response.send('hello world')
  response.send({ hello: 'world' })
})

控制器方法

控制器方法(类似于路由处理程序)接收 HTTP 上下文作为第一个参数。

ts
import { HttpContext } from '@adonisjs/core/http'

export default class HomeController {
  async index({ request, response }: HttpContext) {
  }
}

中间件类

中间件类handle 方法接收 HTTP 上下文作为第一个参数。

ts
import { HttpContext } from '@adonisjs/core/http'

export default class AuthMiddleware {
  async handle({ request, response }: HttpContext) {
  }
}

异常处理程序类

全局异常处理程序类的 handlereport 方法接收 HTTP 上下文作为第二个参数。第一个参数是 error 属性。

ts
import {
  HttpContext,
  HttpExceptionHandler
} from '@adonisjs/core/http'

export default class ExceptionHandler extends HttpExceptionHandler {
  async handle(error: unknown, ctx: HttpContext) {
    return super.handle(error, ctx)
  }

  async report(error: unknown, ctx: HttpContext) {
    return super.report(error, ctx)
  }
}

使用依赖注入注入 HTTP 上下文

如果你在整个应用程序中使用依赖注入,可以通过类型提示 HttpContext 类将 HTTP 上下文注入到类或方法中。

WARNING

确保 #middleware/container_bindings_middleware 中间件已在 start/kernel.ts 文件中注册。此中间件需要从容器中解析特定于请求的值(即 HttpContext 类)。

另请参阅:IoC 容器指南

ts
// title: app/services/user_service.ts
import { inject } from '@adonisjs/core'
import { HttpContext } from '@adonisjs/core/http'

@inject()
export default class UserService {
  constructor(protected ctx: HttpContext) {}
  
  all() {
    // 方法实现
  }
}

为了使自动依赖解析工作,你必须在控制器中注入 UserService。记住,控制器方法的第一个参数始终是上下文,其余参数使用 IoC 容器注入。

ts
import { inject } from '@adonisjs/core'
import { HttpContext } from '@adonisjs/core/http'
import UserService from '#services/user_service'

export default class UsersController {
  @inject()
  index(ctx: HttpContext, userService: UserService) {
    return userService.all()
  }
}

就是这样!UserService 现在将自动接收正在进行的 HTTP 请求的实例。你也可以对嵌套依赖项重复相同的过程。

从应用程序的任何位置访问 HTTP 上下文

依赖注入是一种接受 HTTP 上下文作为类构造函数或方法依赖项,然后依靠容器为你解析它的方式。

但是,重构你的应用程序并在任何地方使用依赖注入并不是硬性要求。你也可以使用 Node.js 提供的异步本地存储从应用程序的任何位置访问 HTTP 上下文。

我们有一个专门的指南介绍异步本地存储的工作原理以及 AdonisJS 如何使用它来提供对 HTTP 上下文的全局访问。

在下面的例子中,UserService 类使用 HttpContext.getOrFail 方法获取正在进行的请求的 HTTP 上下文实例。

ts
// title: app/services/user_service.ts
import { HttpContext } from '@adonisjs/core/http'

export default class UserService {
  all() {
    const ctx = HttpContext.getOrFail()
    console.log(ctx.request.url())
  }
}

以下代码块显示了 UserService 类在 UsersController 中的用法。

ts
import { HttpContext } from '@adonisjs/core/http'
import UserService from '#services/user_service'

export default class UsersController {
  index(ctx: HttpContext) {
    const userService = new UserService()
    return userService.all()
  }
}

HTTP 上下文属性

以下是你可以通过 HTTP 上下文访问的属性列表。随着你安装新包,它们可能会向上下文添加额外的属性。

ctx.request

HTTP Request 类实例的引用。

ctx.response

HTTP Response 类实例的引用。

ctx.logger

为给定 HTTP 请求创建的日志记录器实例的引用。

ctx.route

当前 HTTP 请求的匹配路由。route 属性是 StoreRouteNode 类型的对象。

ctx.params

路由参数对象。

ctx.subdomains

路由子域对象。仅当路由是动态子域的一部分时存在。

ctx.session

为当前 HTTP 请求创建的 Session 实例的引用。

ctx.auth

Authenticator 类实例的引用。了解更多关于认证

ctx.view

Edge 渲染器实例的引用。在视图和模板指南中了解更多关于 Edge。

ctx.ally

Ally Manager 类实例的引用,用于在应用程序中实现社交登录。了解更多关于 Ally

ctx.bouncer

Bouncer 类实例的引用。了解更多关于授权

ctx.i18n

I18n 类实例的引用。在国际化指南中了解更多关于 i18n

扩展 HTTP 上下文

你可以使用宏或 getter 向 HTTP 上下文类添加自定义属性。如果你不熟悉宏的概念,请先阅读扩展 AdonisJS 指南

ts
import { HttpContext } from '@adonisjs/core/http'

HttpContext.macro('aMethod', function (this: HttpContext) {
  return value
})

HttpContext.getter('aProperty', function (this: HttpContext) {
  return value
})

由于宏和 getter 是在运行时添加的,你必须使用模块扩展来告知 TypeScript 它们的类型。

ts
import { HttpContext } from '@adonisjs/core/http'

declare module '@adonisjs/core/http' {
  export interface HttpContext {
    aMethod: () => ValueType
    aProperty: ValueType
  }
}

HttpContext.macro('aMethod', function (this: HttpContext) {
  return value
})

HttpContext.getter('aProperty', function (this: HttpContext) {
  return value
})

在测试期间创建虚拟上下文

你可以使用 testUtils 服务在测试期间创建虚拟 HTTP 上下文。

上下文实例未附加到任何路由;因此,ctx.routectx.params 值将为 undefined。但是,如果被测代码需要,你可以手动分配这些属性。

ts
import testUtils from '@adonisjs/core/services/test_utils'

const ctx = testUtils.createHttpContext()

默认情况下,createHttpContext 方法对 reqres 对象使用假值。但是,你可以为这些属性定义自定义值,如以下示例所示。

ts
import { createServer } from 'node:http'
import testUtils from '@adonisjs/core/services/test_utils'

createServer((req, res) => {
  const ctx = testUtils.createHttpContext({
    req,
    res
  })
})

使用 HttpContext 工厂

testUtils 服务仅在 AdonisJS 应用程序内部可用;因此,如果你正在构建包并需要访问假的 HTTP 上下文,可以使用 HttpContextFactory 类。

ts
import { HttpContextFactory } from '@adonisjs/core/factories/http'
const ctx = new HttpContextFactory().create()