它';是否可以全局获取next.js请求对象?

它';是否可以全局获取next.js请求对象?,next.js,fastify,Next.js,Fastify,我正在将fastfy与next.js一起使用,我需要包括跟踪(requestId是目前的问题)。我现在正在做的是创建一个fastfyonRequest钩子,生成一个requestId值,并在request对象中设置它(也可以作为请求头)。我想要访问此请求对象的原因有两个: 在logger对象中(pino在本例中,我希望在所有自定义服务器端日志中包含requestId) 在所有需要向其他服务发出的请求中,需要在标题中包含requestId 也许我错过了一些琐碎的事情,我没有用最好的方式去做 这里是

我正在将
fastfy
next.js一起使用,我需要包括跟踪(
requestId
是目前的问题)。我现在正在做的是创建一个
fastfy
onRequest钩子,生成一个
requestId
值,并在request对象中设置它(也可以作为请求头)。我想要访问此请求对象的原因有两个:

  • 在logger对象中(
    pino
    在本例中,我希望在所有自定义服务器端日志中包含
    requestId
  • 在所有需要向其他服务发出的请求中,需要在标题中包含
    requestId
  • 也许我错过了一些琐碎的事情,我没有用最好的方式去做

    这里是一些片段

    这是我生成请求ID的方式

    const fastfy=fastfyFactory({
    记录器,//记录器配置(具有自定义配置的Pino实例,请参阅下文)
    genReqId:()=>{
    return Math.random()
    .托斯特林(36)
    .切片(-6);
    }
    });
    
    引脚实例

    const pino=require('pino');
    常数记录器=引脚({
    messageKey:'消息',
    打印前:正确,
    changeLevelName:“严重性”,
    useLevelLabels:true,
    基数:{
    serviceContext:{
    服务:“网络”
    }
    },
    级别:'info'
    });
    module.exports={
    记录器
    };
    
    这是一个插件,用于获取生成的reqId并将其设置为请求对象中的查询属性

    const tracing=函数跟踪(fastfy、opt、next){
    fastfy.addHook('onRequest',(req、res、nextRequest)=>{
    常量{id}=req;
    const logger=fastfy.log.child({reqId:id});
    req.query.reqId=id;
    fastfy.log=logger;//覆盖当前的fastfy记录器,以便在所有自定义日志中包含reqId
    nextRequest();
    });
    next();
    };
    跟踪[Symbol.for('skip-override')]=true;
    module.exports=跟踪;
    

    我在使用
    fastfy.log.info(…)
    时没有问题,因为如何在每个请求中覆盖记录器,它将包含
    reqId
    作为子日志。问题是,我想创建一个通用记录器用于任何部件,而fastify logger在React组件中不可用(例如,在
    getInitialProps
    中写入日志)。另一个重要的想法是,我需要在我发送给其他服务的所有请求(例如:获取数据时)中包含此
    reqId
    ,这就是为什么我试图将此值存储在请求对象中,但需要获取它。

    从以下项目构建开始:

    npx create-next-app --example custom-server-fastify custom-server-fastify-app
    
    并使用以下命令更改
    server.js

    const Next = require('next')
    const Fastify = require('fastify')
    
    // your pino config
    const fastify = Fastify({
      logger: {
        level: 'info',
        prettyPrint: true,
        changeLevelName: 'severity',
        useLevelLabels: true,
        base: {
          serviceContext: {
            service: 'web'
          }
        }
      },
      genReqId: () => { return Math.random().toString(36).slice(-6) }
    })
    
    // your plugin
    const aPlugin = function yourPlugin (fastify, opts, next) {
      fastify.addHook('onRequest', (request, reply, next) => {
        request.log.info('hello')
        const { id } = request
        request.query.reqId = id
        next()
      })
      next()
    }
    aPlugin[Symbol.for('skip-override')] = true
    fastify.register(aPlugin)
    
    [.... other generated code]
    const port = parseInt(process.env.PORT, 10) || 3000
    
    [.... other generated code]
          fastify.get('/*', (req, reply) => {
            console.log('-------->', req.id, req.query.reqId) // both your id is ok
            return app.handleRequest(req.req, reply.res).then(() => {
              reply.sent = true
            })
    [.... other generated code]
          })
    
    然后:

    它将打印出:

    [1558441374784] INFO : Server listening at http://127.0.0.1:3000
        serviceContext: {
          "service": "web"
        }
    > Ready on http://localhost:3000
    [1558441405416] INFO : incoming request
        serviceContext: {
          "service": "web"
        }
        reqId: "2i810l"
        req: {
          "method": "GET",
          "url": "/",
          "hostname": "localhost:3000",
          "remoteAddress": "127.0.0.1",
          "remotePort": 57863
        }
    req id ----> 2i810l
    --------> 2i810l 2i810l
    [ event ] build page: /
    [ wait ]  compiling ...
    [1558441406171] INFO : request completed
        serviceContext: {
          "service": "web"
        }
        reqId: "2i810l"
        res: {
          "statusCode": 200
        }
        responseTime: 753.012099981308
    
    因此,我认为误解在于request对象是fastfy请求,而不是Node.js“low-level”请求对象,它可以通过
    request.req
    访问

    此外,运行
    fastfy.log=logger
    是危险的,因为它意味着每个请求都会覆盖并创建一个新的记录器,并更改fastify实例的记录器,这是不安全的,如图所示,这是不必要的

    如果您想要更多的子记录器(每个示例的每个路由前缀),我建议探索/使用


    编辑:

    现在,自定义钩子打印:

    [1558443540483] INFO : hello
        serviceContext: {
          "service": "web"
        }
        reqId: "zjuhw2"
    

    从具有以下内容的项目构建开始:

    npx create-next-app --example custom-server-fastify custom-server-fastify-app
    
    并使用以下命令更改
    server.js

    const Next = require('next')
    const Fastify = require('fastify')
    
    // your pino config
    const fastify = Fastify({
      logger: {
        level: 'info',
        prettyPrint: true,
        changeLevelName: 'severity',
        useLevelLabels: true,
        base: {
          serviceContext: {
            service: 'web'
          }
        }
      },
      genReqId: () => { return Math.random().toString(36).slice(-6) }
    })
    
    // your plugin
    const aPlugin = function yourPlugin (fastify, opts, next) {
      fastify.addHook('onRequest', (request, reply, next) => {
        request.log.info('hello')
        const { id } = request
        request.query.reqId = id
        next()
      })
      next()
    }
    aPlugin[Symbol.for('skip-override')] = true
    fastify.register(aPlugin)
    
    [.... other generated code]
    const port = parseInt(process.env.PORT, 10) || 3000
    
    [.... other generated code]
          fastify.get('/*', (req, reply) => {
            console.log('-------->', req.id, req.query.reqId) // both your id is ok
            return app.handleRequest(req.req, reply.res).then(() => {
              reply.sent = true
            })
    [.... other generated code]
          })
    
    然后:

    它将打印出:

    [1558441374784] INFO : Server listening at http://127.0.0.1:3000
        serviceContext: {
          "service": "web"
        }
    > Ready on http://localhost:3000
    [1558441405416] INFO : incoming request
        serviceContext: {
          "service": "web"
        }
        reqId: "2i810l"
        req: {
          "method": "GET",
          "url": "/",
          "hostname": "localhost:3000",
          "remoteAddress": "127.0.0.1",
          "remotePort": 57863
        }
    req id ----> 2i810l
    --------> 2i810l 2i810l
    [ event ] build page: /
    [ wait ]  compiling ...
    [1558441406171] INFO : request completed
        serviceContext: {
          "service": "web"
        }
        reqId: "2i810l"
        res: {
          "statusCode": 200
        }
        responseTime: 753.012099981308
    
    因此,我认为误解在于request对象是fastfy请求,而不是Node.js“low-level”请求对象,它可以通过
    request.req
    访问

    此外,运行
    fastfy.log=logger
    是危险的,因为它意味着每个请求都会覆盖并创建一个新的记录器,并更改fastify实例的记录器,这是不安全的,如图所示,这是不必要的

    如果您想要更多的子记录器(每个示例的每个路由前缀),我建议探索/使用


    编辑:

    现在,自定义钩子打印:

    [1558443540483] INFO : hello
        serviceContext: {
          "service": "web"
        }
        reqId: "zjuhw2"
    

    我想这项功能已经被via支持了,你试过了吗?@ManuelSpigolon是的,但是这项功能允许设置一个自定义函数来生成reqId。我目前正在使用,但问题是在fastify logger的范围之外,我无法访问此属性(reqId)。我尝试使用cls hooked来存储生成的reqId,但我无法从任何React组件使用它(可能是做错了什么)。您是否有一些片段让我更好地理解上下文?@ManuelSpigolon我已经在问题中添加了片段我有一个工作片段,最后一件事:你能添加你的pino配置吗?我想这项功能已经被via支持了,你试过了吗?@ManuelSpigolon是的,但这项功能允许设置一个自定义函数来生成reqId。我目前正在使用,但问题是在fastify logger的范围之外,我无法访问此属性(reqId)。我尝试使用cls hooked来存储生成的reqId,但我无法从任何React组件使用它(可能是做错了什么)。您是否有一些片段让我更好地理解上下文?@ManuelSpigolon我已经在问题中添加了片段我有一个工作片段,最后一件事:你能添加你的pino配置吗?这个问题并没有解决。
    fastfy.log=记录器的用途是因为如果您尝试编写自定义日志,您将看到未包含reqId(不是fastify写入的默认日志,如传入请求和请求完成,您显示的那些日志与包含reqId的日志配合良好),我需要它。这是我的主要问题(可能不太清楚,对不起我的英语),如何在React组件中获得此reqId OK,我将签出
    我已更新响应以在您记录某些内容时打印reqId
    编辑答案以修复此问题,仍然在React组件中检查id genReqId:()=>{return Math.random()皮诺中的切片(-6)}是将基因