Express集成Nunjucks模板时抛出ERR_HTTP_HEADERS_SENT错误求助
Nunjucks集成Inversify+Express时ERR_HTTP_HEADERS_SENT错误的原因与解决办法
问题场景
基于ESModule TypeScript的Node.js项目,使用Express.js和Inversify框架,集成Nunjucks作为模板引擎时,访问渲染njk模板的接口会抛出ERR_HTTP_HEADERS_SENT错误。切换为Pug模板或返回纯字符串时一切正常,且此前类似配置曾成功运行。
错误栈
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client at ServerResponse.setHeader (node:_http_outgoing:659:11) at ServerResponse.header (/home/bailando/projects/learning-platform/node_modules/express/lib/response.js:794:10) at ServerResponse.contentType (/home/bailando/projects/learning-platform/node_modules/express/lib/response.js:624:15) at ServerResponse.send (/home/bailando/projects/learning-platform/node_modules/express/lib/response.js:149:14) at done (/home/bailando/projects/learning-platform/node_modules/express/lib/response.js:1045:10) at /home/bailando/projects/learning-platform/node_modules/nunjucks/src/environment.js:28:5 at RawTask.call (/home/bailando/projects/learning-platform/node_modules/asap/asap.js:40:19) at flush (/home/bailando/projects/learning-platform/node_modules/asap/raw.js:50:29) at process.processTicksAndRejections (node:internal/process/task_queues:77:11) { code: 'ERR_HTTP_HEADERS_SENT' }
相关代码
项目配置文件index.ts
import 'dotenv/config'; import 'reflect-metadata'; import container from './ioc.config.js'; import nunjucks from 'nunjucks'; import { InversifyExpressServer } from 'inversify-express-utils'; const server = new InversifyExpressServer(container); server.setConfig((app) => { nunjucks.configure('views', { autoescape: true, express: app }); app.set('view engine', 'njk'); }); const app = server.build(); app.listen(3000, () => { console.log('Server started on http://localhost:3000'); });
控制器文件home.controller.ts
import { Request, Response } from 'express'; import { controller, httpGet } from 'inversify-express-utils'; @controller('/') export class HomeController { constructor() {} @httpGet('/') public async getUsers(_: Request, res: Response) { res.render('home'); } }
模板文件home.njk
内容为纯文本:Hello world
原因分析
核心问题在于控制器的getUsers方法被标记为async。Inversify-express-utils会将异步方法的返回值(一个Promise)视为未完成的响应处理,当Nunjucks通过res.render完成响应发送后,框架会在Promise resolve时尝试再次处理响应,导致重复设置HTTP头,触发ERR_HTTP_HEADERS_SENT错误。
而Pug模板或纯字符串返回时未触发该错误,是因为它们的响应处理逻辑与Nunjucks的异步调度机制存在差异,或者此前的配置中控制器方法并未使用async关键字。
解决办法
方案1:移除async关键字
由于res.render本身是基于回调的异步操作,不需要用async包裹,直接移除即可:
import { Request, Response } from 'express'; import { controller, httpGet } from 'inversify-express-utils'; @controller('/') export class HomeController { constructor() {} @httpGet('/') public getUsers(_: Request, res: Response) { res.render('home'); } }
方案2:保留async并手动控制Promise完成时机
如果业务逻辑需要保留async,可以将res.render包装为Promise,确保在渲染完成后再resolve,避免框架重复处理:
import { Request, Response } from 'express'; import { controller, httpGet } from 'inversify-express-utils'; @controller('/') export class HomeController { constructor() {} @httpGet('/') public async getUsers(_: Request, res: Response) { await new Promise<void>((resolve) => { res.render('home', resolve); }); } }
内容的提问来源于stack exchange,提问作者Pan Wolodyjowsky
相关产品推荐
相关产品推荐

