Skip to main content

Context 对象

context 是中间件的核心,包含了请求的所有信息。

主要属性

属性描述
context.requestHTTP 请求参数(URL、方法、请求头、请求体等)
context.response[Readonly] HTTP 响应代理对象,可多次读取响应体
context.res原始 Fetch Response 对象
context.options通过 .option() 设置的自定义选项
context.output[Writeonly] 设置请求的返回值(当未使用 .resolveWith() 时)
context.data请求级别的共享数据,在请求完成后自动清理
context.global全局共享数据,不会随请求结束而销毁
context.orchestration[Readonly] 详见进阶 - 中间件调度与执行
context.locationId[Readonly] 请求代码的位置标识(文件路径+行号)

context.data

context.data 是一个对象,用于在同一请求的多个中间件之间共享数据。并在请求完成后销毁。

示例:

import { KeqMiddleware } from "keq"

const timerMiddleware: KeqMiddleware = async (context, next) => {
  context.emitter.on('fetch:before', (ctx) => {
    ctx.data.timer = { start: Date.now() }
  })

  context.emitter.on('fetch:after', (ctx) => {
    const duration = Date.now() - ctx.data.timer.start
    console.log(`请求耗时: ${duration}ms`)
  })
  await next()
}

context.options

通过 .option() 方法设置的自定义选项。

内置选项及其默认值:

选项默认值描述
context.options.fetchAPIglobal.fetch用于发送请求的 Fetch API 实现
context.options.resolveWith"intelligent"响应体解析方式
context.options.retry.timesundefined重试次数
context.options.retry.delayundefined重试延迟时间(毫秒)
context.options.retry.onundefined自定义重试条件函数
context.options.timeoutundefined请求超时时间(毫秒)
context.options.flowControlundefined并发控制模式
context.options.moduleundefined模块元信息(name、pathname、method),通常由 @keq-request/cli 自动生成

添加自定义选项:

import { KeqMiddleware } from "keq"

// 扩展类型定义
declare module "keq" {
  interface KeqOptions<T> {
    customOption(value: string): Keq<T>
  }
}

const customMiddleware: KeqMiddleware = async (context, next) => {
  // 读取自定义选项
  const value = context.options.customOption
  console.log("Custom option:", value)

  await next()
}

context.global

全局共享数据,不会随请求结束而销毁。使用时需要特别注意内存管理。

示例:

import { KeqMiddleware } from "keq"

const key = Symbol('myMiddleware')

const middleware: KeqMiddleware = async (context, next) => {
  context.global[key] = { startTime: Date.now() }

  try {
    await next()
  } finally {
    // 及时清理
    delete context.global[key]
  }
}
context.data VS context.options VS context.global
特性context.datacontext.optionscontext.global
设置方式直接赋值.option() 方法或直接赋值直接赋值
生命周期请求结束自动清理请求结束自动清理手动清理
作用域单个请求单个请求全局共享
用途中间件间传递数据向中间件传递配置跨请求共享状态

context.request

包含发送 HTTP 请求所需的所有参数:

属性描述
context.request.url请求 URL 对象
context.request.__url__只读 合并了路由参数后的完整请求 URL
context.request.methodHTTP 方法('get', 'post', 'put', 'patch', 'delete', 'head')
context.request.headers请求头(Headers 对象)
context.request.body请求体
context.request.routeParams路由参数对象
context.request.abort()中止当前请求
context.request.credentialsFetch API 的 credentials 选项
context.request.modeFetch API 的 mode 选项
context.request.cacheFetch API 的 cache 选项
context.request.redirectFetch API 的 redirect 选项
context.request.referrerFetch API 的 referrer 选项
context.request.referrerPolicyFetch API 的 referrerPolicy 选项
context.request.integrityFetch API 的 integrity 选项
context.request.keepaliveFetch API 的 keepalive 选项

示例:修改请求参数

import { KeqMiddleware } from "keq"

const modifyRequestMiddleware: KeqMiddleware = async (context, next) => {
  // 修改 URL
  context.request.url.searchParams.set("timestamp", Date.now().toString())

  // 添加请求头
  context.request.headers.set("X-Custom-Header", "value")

  // 修改请求方法
  context.request.method = "post"

  await next()
}

路由参数

使用 context.request.routeParamscontext.request.__url__ 处理路由参数:

import { request } from "keq"

request.use(async (context, next) => {
  console.log("原始 URL:", context.request.url.href)
  console.log("路由参数:", context.request.routeParams)
  console.log("实际 URL:", context.request.__url__.href)

  await next()
})

await request.get("/users/{id}").params("id", "123")
// 原始 URL: /users/{id}
// 路由参数: { id: "123" }
// 实际 URL: /users/123

context.response

context.response 是原始 Response 对象的代理,解决了 Response 对象的方法(如 .json().text())只能调用一次的限制,允许多个中间件安全地读取响应体。

示例:读取响应体

import { KeqMiddleware } from "keq"

const logResponseMiddleware: KeqMiddleware = async (context, next) => {
  await next()

  if (context.response) {
    // 多个中间件都可以安全地读取 JSON
    const data = await context.response.json()
    console.log("响应数据:", data)
    console.log("状态码:", context.response.status)
    console.log("响应头:", context.response.headers)
  }
}

const cacheMiddleware: KeqMiddleware = async (context, next) => {
  await next()

  if (context.response) {
    // 再次读取同样的 JSON,不会出错
    const data = await context.response.json()
    localStorage.setItem("cache", JSON.stringify(data))
  }
}

context.res

context.res 是原始的 Fetch Response 对象。大多数情况下应该使用 context.response,只有在需要访问原始 Response 对象时才使用 context.res

context.output

用于设置请求的返回值。当未使用 .resolveWith() 时,可以通过 context.output 自定义返回内容:

import { KeqMiddleware } from "keq"

const transformMiddleware: KeqMiddleware = async (context, next) => {
  await next()

  if (context.response) {
    const data = await context.response.json()
    // 设置自定义返回值
    context.output = {
      success: true,
      data: data,
      timestamp: Date.now()
    }
  }
}
warning

设置 context.output 后,请求将返回该值,而不会根据 Content-Type 自动解析响应体。

context.orchestration

中间件编排器,提供中间件执行状态和 fork 能力,详见进阶 - 中间件调度与执行