You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在TypeORM自定义Logger中获取请求Header等请求信息

TypeORM自定义Logger获取请求上下文解决方法

问题根本原因

queryRunner.data 是TypeORM预留的自定义数据存储字段,不会自动填充任何内容,你没有主动往该字段写入请求、用户相关数据的前提下,默认就是空值。

方案1:手动绑定数据到queryRunner(适合愿意调整业务代码的场景)

你需要在请求生命周期的入口,手动创建请求级的queryRunner,写入你需要的上下文数据,后续所有业务逻辑的数据库操作都使用该queryRunner执行,即可在Logger中读取到对应数据。

实现步骤:

  1. 新增全局请求中间件,创建请求级queryRunner并绑定上下文
// 以Express框架为例
import { dataSource } from './your-typeorm-config'
import { parseJwt } from './your-jwt-util'

app.use(async (req, res, next) => {
  // 解析JWT获取用户信息
  const token = req.headers.authorization?.split(' ')[1]
  const user = token ? parseJwt(token) : null

  // 为当前请求创建独立的queryRunner
  const queryRunner = dataSource.createQueryRunner()
  // 写入自定义数据
  queryRunner.data.request = req
  queryRunner.data.user = user
  // 挂载到req对象上供业务层使用
  req.queryRunner = queryRunner

  // 请求结束后释放queryRunner
  res.on('finish', async () => {
    await queryRunner.release()
  })

  next()
})
  1. 业务层所有数据库操作,统一使用挂载在req上的queryRunner执行,示例:
// 错误写法:用全局manager/repository,不会携带你绑定的data
// await getRepository(User).save(user)

// 正确写法:用当前请求的queryRunner执行操作
await req.queryRunner.manager.getRepository(User).save(user)

方案2:用AsyncLocalStorage存储请求上下文(无需修改业务代码,更推荐)

如果你不想调整现有业务代码的数据库调用逻辑,可以用Node.js原生的AsyncLocalStorage存储请求上下文,直接在Logger中读取即可,完全不需要依赖queryRunner.data。

实现步骤:

  1. 新建全局上下文存储实例
import { AsyncLocalStorage } from 'async_hooks'

export const requestContext = new AsyncLocalStorage<{
  user?: { id: number; username: string }
  requestUrl?: string
}>()
  1. 新增全局中间件,把上下文存入AsyncLocalStorage
import { parseJwt } from './your-jwt-util'

app.use((req, res, next) => {
  // 解析JWT获取用户信息
  const token = req.headers.authorization?.split(' ')[1]
  const user = token ? parseJwt(token) : null

  // 将当前请求的上下文存入AsyncLocalStorage
  requestContext.run(
    {
      user,
      requestUrl: req.url
    },
    () => next()
  )
})
  1. 调整自定义Logger的逻辑,直接读取上下文
import { requestContext } from './your-context-file'

public logQuery(query: string, parameters?: any[], queryRunner?: QueryRunner): any {
  const type = query.substring(0, 6);
  if ((type === 'INSERT' || type === 'UPDATE' || type === 'DELETE') && !query.includes('INSERT INTO "log"')) {
    const log = new Log();

    // 直接从AsyncLocalStorage获取上下文
    const context = requestContext.getStore()
    const requestUrl = context?.requestUrl ? `(${context.requestUrl}) ` : '';
    console.log(`${requestUrl}executing query: `);

    log.query = query;
    log.parameters = parameters?.toString();
    log.type = type;
    log.userId = context?.user?.id // 直接拿到发起操作的用户ID

    getRepository(Log).save(log).then();
  }
}

注意事项

  • AsyncLocalStorage需要Node.js版本 >= 12.17.0,目前绝大多数后端项目都满足该要求
  • 该方案不需要修改任何现有业务的数据库调用代码,侵入性极低

内容的提问来源于stack exchange,提问作者Wilson Silva

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.08 00:21:02