【问题标题】:Acknowledge Response sent too late; NodeJS Express Asynchrone Response确认响应发送太晚; NodeJS Express 异步响应
【发布时间】:2021-03-15 13:25:50
【问题描述】:

我正在使用带有 express 的 NodeJS。

我收到信息发布者的请求。我必须在收到请求后立即发回确认响应。然后我应该处理请求并返回响应。

根据他们的日志,我发回的确认响应太晚了,而且是在推送了真正的响应之后。这是错误的,不是我想要的。我想跟随这张图片中的模型:

所以我有一个带有以下代码的 router.js 文件:

app.post('/import/message.io', Importer.handleMessage);

在导入控制器中,handleMessage 函数处理请求:

function handleMessage(req, res){
    let otaRequestBuffer = [];
    req.on('readable', () => {
        let data;
        while (data = req.read()) {
            otaRequestBuffer.push(data.toString());
        }
    });
    req.on('end', () => {
        let otaRequest = otaRequestBuffer.join('');
        try {
                let parser = new DOMParser();
                let xmlDoc = parser.parseFromString(otaRequest, "text/xml");
                let soapHeader = parseSoapHeader(xmlDoc);
                const soapAction = req.headers['soapaction'].toString();

                // Acknowledge the request; The soapHeader is used in here too. That is why it is after the code above
                res.writeHead(200);
                res.write(
                    `<?xml version='1.0' encoding='utf-8'?> ...
                   `
                );
                res.end();
                // Kick off a new job by adding it to the work queue; Response is send in the consumer.js of this job
                let job = jobs.create('worker-job', args);

                job.on('complete', function(result){
                console.log('Job completed');
                // Other job.on code would be here
                })
       } catch (error) {
                console.log(error);
       } finally {
          console.log('DevInfo: Finally called here');
       }
});

其他见解:

  • 因此确认响应的格式正确。
  • 当我在本地测试时,我会立即收到确认
  • 信息发布者的日志在这里

根据日志,他们的实际响应(第 5 行)似乎在确认响应(第 1 行)之前被推送给他们。

我上面粘贴的代码示例可以做到这一点吗?

感谢您的帮助。

【问题讨论】:

    标签: node.js asynchronous request response


    【解决方案1】:

    看起来完全有可能在客户端收到确认之前发送真正的响应(推送)。由于 response.end() 是异步的(例如,调用将在响应发送之前完成),我们实际上是在竞速

    res.end();
    

    let job = jobs.create('worker-job', args);
    

    这是一种只有在投入生产时才会看到的烦人的事情!

    也许您可以在调用 end() 回调后尝试排队您的工作。例如

    res.end(() => { 
        console.log("End callback, response stream is complete, starting job...");
        // Kick off a new job by adding it to the work queue; Response is send in the consumer.js of this job
        let job = jobs.create('worker-job', args);
        job.on('complete', function(result){
            console.log('Job completed');
            // Other job.on code would be here
        })
    });
    

    自从(来自 Node.js 文档)...

    如果指定了回调,它将在响应流完成时调用。

    https://nodejs.org/api/http.html#http_response_end_data_encoding_callback

    (这是Express用response.end包装的方法) http://expressjs.com/en/5x/api.html#res.end

    我还建议在您的服务器上记录详细的时间戳,精确到毫秒,这样您就可以准确地看到调用发生的时间。

    setTimeout 方法当然值得一试,它可能会得到你想要的结果:

    // Set delay as appropriate
    const delayMs = 2000;
    setTimeout(() => { 
        console.log("Timeout complete, starting job...");
        // Kick off a new job by adding it to the work queue; Response is send in the consumer.js of this job
        let job = jobs.create('worker-job', args);
        job.on('complete', function(result){
            console.log('Job completed');
            // Other job.on code would be here
        })
    }, delayMs);
    

    【讨论】:

    • 感谢您的回复!这对我帮助很大。我会及时通知你这在生产中的表现!
    • 不幸的是它不起作用。可以选择 setTimeout 吗?
    • 是的,这可能是您的下一个选择,我会将其添加到答案中!
    • 3000 毫秒的超时也不起作用:/。奇怪......我很快就会深入研究它。
    • 也许 res.send() 是 router.js 文件中的替代方法,因为这也是同步的
    猜你喜欢
    • 2017-12-21
    • 1970-01-01
    • 1970-01-01
    • 2020-04-17
    • 1970-01-01
    • 1970-01-01
    • 2014-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多