首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >云函数错误在两个调用中有一次:“error [ERR_HTTP_HEADERS_SENT]:无法在标头发送到客户端后设置它们”

云函数错误在两个调用中有一次:“error [ERR_HTTP_HEADERS_SENT]:无法在标头发送到客户端后设置它们”
EN

Stack Overflow用户
提问于 2021-06-10 13:17:45
回答 1查看 188关注 0票数 0

我有一个云函数,它调用一个复杂的任务(包含许多不同的异步任务)。在这些任务结束时,将发送一个事件“已完成”,并由将终止的云函数捕获,如:

代码语言:javascript
复制
exports.myFunction = functions.https.onRequest(async (request: any, response: any) => {
  cors(request, response, async () => {
    doSomethingComplex();                          // no returned value possible here, but many asynchronous tasks done
    eventEmitter.on('finished', (data) => {        // finished is properly sent at the end of the asynchronous tasks
       functions.logger.debug('done : ', data);    // is always clean with only 1 occurence at each function call
       response.send({something: data.something}); // <--- THIS IS WHERE THE ERROR OCCURE
    }
  });
});

目前,每个异步任务都在每个调用上完美地完成。但是,每两次中就有一次,response.send()与以下错误堆栈发生错误:

代码语言:javascript
复制
at ServerResponse.send (/layers/google.nodejs.functions-framework/functions-framework/node_modules/express/lib/response.js:170:12) 

at ServerResponse.json (/layers/google.nodejs.functions-framework/functions-framework/node_modules/express/lib/response.js:267:15) 

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client 

at ServerResponse.setHeader (_http_outgoing.js:530:11)

at ServerResponse.send (/layers/google.nodejs.functions-framework/functions-framework/node_modules/express/lib/response.js:158:21) 

at ServerResponse.header (/layers/google.nodejs.functions-framework/functions-framework/node_modules/express/lib/response.js:771:10) 

at EventEmitter.<anonymous> (/workspace/lib/src/index.js:235:37) 
Function execution took 3354 ms, finished with status: 'crash'

我试着使用response.end(),我试图返回response.send(),但是一切都失败了。

我还记录了每一个异步任务,以确保它们在发送' finished‘事件之前都完成了,并且该部分的所有内容都是干净的。

我不明白如何在云函数被调用时精确地调用response.send()一次,但仍然每两次调用就触发一次Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client (1次成功,1次错误,1次成功,1次错误)。

这对我来说是有意义的,就像云函数在response.send()之后没有关闭一样(根据this answer,这是不可能的)

有人有主意吗?我会非常感激的!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-06-10 15:53:54

answer you linked讨论了云函数的生命周期。

当您向您的函数发出请求时,云函数网关将检查是否有任何“云函数执行器”是空闲/陈旧/非活动的。如果没有一个空闲,一个新的执行器将被冷启动并发送请求。如果一个人空闲,该执行者将被发送请求,以节省冷启动一个新的执行器。在处理请求时,通过发送返回结果(对于HTTPS事件云函数,这是通过使用res.end()或其变体之一完成的;对于大多数其他云函数,这是通过解析返回的Promise链来完成的),从而告诉网关“我完成了”。

返回结果后,“”被标记为空闲。空闲时,任何网络请求都会被阻塞,该执行器可能在任何时候被关闭(终止)。如上所述,如果一个空闲函数处理另一个请求,如果您没有正确地处理生命周期流,它可能会导致奇怪的副作用,它可能再次被标记为active。

因此,要正确处理流,您需要遵循以下步骤:

  1. 验证请求(检查重试、语法错误、缺少身份验证)并在必要时取消它。
  2. do所有您需要做的工作的
  3. 返回适当的结果。

G 212

如果您需要做的工作需要一段时间,请将作业描述写入数据库(Firestore/RTDB),以便它可以由写入数据库触发的不同云函数处理,然后将结果发回作为查找该作业更新位置的说明。

从您的代码来看,eventEmitter似乎被定义为一个全局对象,当它在doSomethingComplex()中完成工作时,它会释放出"finished"事件。当第一次触发myFunction时,一切都很好。但是,如果myFunction被重用,第二个"finished"事件将被触发。这对于当前请求很好,但是前面的请求仍然订阅eventEmitter,并试图发送第二个响应,从而导致所看到的错误。

你有三个选择:

  • 只订阅一个“已完成”事件。(解决方案评级:糟糕)(考虑一下如果失败了,但是稍后会请求succeeds)
  • Return -- eventEmitter的私有版本来自doSomethingComplex() )。(解决方案评级:将Okay)
  • Convert doSomethingComplex()转换为Promise-returning函数。(解决方案评级:最佳)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67921964

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档