Context

未匹配的标注

HTTP 上下文( context) 是一个比较特殊的对象。 context 对象持有request body, cookies, headers 当前登录的logged in user,以及给定 HTTP 的更多请求信息。

HTTP context 采用引用传递的方式,传递给路由(route)、中间件(middleware),HTTP hooks 和异常处理程序。

Route.get('/', ({ request, auth, response }) => {
  /**
   * 请求 URL
   */
  console.log(request.url())

  /**
   * 请求body + 参数
   */
  console.log(request.all())

  /**
   * 响应
   */
  response.send('hello world')
  response.send({ hello: 'world' })

  /**
   *  当配置身份验证时,可用
   */
  console.log(auth.user)
})

确保在控制器方法(controller method)中,明确定义context的类型。

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

class HomeController {
  public async index({ request, response }: HttpContextContract) {

  }
}

是否与 Express 中的 reqres 对象有某些关联?

你不会在 AdonisJS 中看到任何 reqres 对象,这是因为所有的一切(包括请求和响应)都是 HTTP 上下文(context)的一部分。

此外,我们鼓励你将自定义属性添加到 ctx 对象,而不是 request 对象。请参阅 扩展上下文

访问 HTTP 上下文

AdonisJS 使用 Node.js AsyncLocalStorage 使 HTTP 上下文在程序内的任何位置都可以访问到.

你可以按如下方式访问当前请求的上下文:

注意:在使用 HttpContext.get 方法之前,请务必仔细阅读 Async Local Storage 指南。

import HttpContext from '@ioc:Adonis/Core/HttpContext'

class SomeService {
  public async someOperation() {
    const ctx = HttpContext.get()
  }
}

属性

以下是 HTTP 上下文中可用的属性列表,当你将安装新包时,它们也可能会向该对象添加更多属性。

Output of ctx.inspect({ depth: 0 })

请求

参考 HTTP 请求

Route.get('/', async ({ request }) => {})

响应

参考 HTTP 响应

Route.get('/', async ({ response }) => {})

日志

对日志记录器实例的引用。为每个 HTTP 请求创建一个具有唯一 request IDchild logger 实例。

Route.get('/', async ({ logger }) => {})

路由

对当前 HTTP 请求匹配路由,路由具有以下属性。

  • pattern: 路由模式
  • handler: 路由处理器
  • middleware: 路由中间件数组
  • name: 路由名称 (如果有)
Route.get('/', async ({ route }) => {})

参数

路由参数对象。

Route.get('users/:id', async ({ params }) => {
  console.log(params.id)
})

路由子域

路由子域的对象,仅当路由在域中注册时可用。

Route.group(() => {
  Route.get('/', async ({ subdomains }) => {
    console.log(subdomains.tenant)
  })
}).domain(':tenant.adonisjs.com')

会话

参考 Session 对象,仅在安装 @adonisjs/session 包时可用。

Route.get('/', async ({ session }) => {
  session.get('cart_value')
})

认证

参考 Auth 对象,仅在安装 @adonisjs/auth 包时可用。

Route.get('/', async ({ auth }) => {
  console.log(auth.user)
})

视图

参考 视图对象,仅在安装 @adonisjs/view 包时可用。

Route.get('/', async ({ view }) => {
  return view.render('welcome')
})

合作

参考 合作对象,仅在安装 @adonisjs/ally 软件包时可用。

Route.get('/', async ({ ally }) => {
  return ally.use('github').redirect()
})

安检

参考 Bouncer 对象,仅在安装 @adonisjs/bouncer 包时可用。

Route.get('/', async ({ bouncer }) => {
  await bouncer.authorize('viewPost', post)
})

i18n

参考 I18n 对象,仅在安装 @adonisjs/i18n 软件包时可用。

Route.get('/', async ({ i18n }) => {
  await i18n.formatCurrency(100, { currency: 'EUR' })
})

扩展上下文

HTTP 上下文对象可由其他包或你自己的应用程序代码扩展,一个常见的用法是在中间件中添加自定义属性,例如:

import geoip from 'geoip-lite'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default class UserLocationMiddleware {
  public async handle(ctx: HttpContextContract, next: () => Promise<void>) {
    ctx.location = geoip.lookup(ctx.request.ip())
    await next()
  }
}

在这里,我们向 ctx 添加了一个自定义 location 属性,你可以在路由处理程序或即将推出的中间件中访问该属性。

通知 TypeScript 自定义属性

location 属性是在运行时添加的;所以 TypeScript 不知道它。为了告知 TypeScript 该属性的存在,我们将使用 declaration merging 并将属性添加到 HttpContextContract 接口。

在路径 contracts/context.ts 处创建一个新文件(文件名不重要)并在其中粘贴以下内容:

// 文件名: contracts/context.ts
declare module '@ioc:Adonis/Core/HttpContext' {
  import { Lookup } from 'geoip-lite'

  interface HttpContextContract {
    location: Lookup | null
  }
}

这样,TypeScript 就不会抱怨 ctx 对象上缺少的属性。


使用 getter 和宏

你还可以使用 getter 和宏将自定义属性添加到 ctx 对象。在前面的示例中,我们向 ctx 对象添加了一个 实例属性。但是,getter 和宏会在 类的原型 上添加属性。

此外,这次不需要创建中间件,因为你只需定义一次宏/getter,就可用于 HttpContext 类的所有实例。

打开预设的 providers/AppProvider.ts 文件并将以下代码粘贴到 boot 方法中:

// 文件名: providers/AppProvider.ts
import geoip from 'geoip-lite'
import { ApplicationContract } from '@ioc:Adonis/Core/Application'

export default class AppProvider {
  public static needsApplication = true

  constructor(protected app: ApplicationContract) {}

  public async boot() {
    const HttpContext = this.app.container.use('Adonis/Core/HttpContext')

    HttpContext.getter('location', function location() {
      return geoip.lookup(this.request.ip())
    })
  }
}

默认情况下,每次访问都会评估 getter。但是,你也可以将它们标记为单例,如下所示:

HttpContext.getter(
  'location',
  function location() {
    return geoip.lookup(this.request.ip())
  },
  true // 👈 注册为单例
)

Getter 只能作为属性访问,但是,宏既可以是属性,也可以是方法。

HttpContext.macro('getLocation', function location() {
  return geoip.lookup(this.request.ip())
})

// 调用方式
ctx.getLocation()

或添加一个字面值。

HttpContext.macro('pid', process.pid)

// 调用方式
ctx.pid

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/adonisjs/5.x/ht...

译文地址:https://learnku.com/docs/adonisjs/5.x/ht...

上一篇 下一篇
贡献者:5
讨论数量: 0
发起讨论 查看所有版本


暂无话题~