Express实现XML转JSON时报ERR_HTTP_HEADERS_SENT错误的原因及缺陷排查
错误触发原因
ERR_HTTP_HEADERS_SENT 错误的核心触发原因是同一个HTTP请求下,你尝试向客户端发送了两次及以上的响应:
- 你在
/json_results路由中首先调用了res.render()渲染pug模板,此时已经向客户端发送了HTML格式的响应头和内容 produce_xml是异步函数,请求完成后的回调中你又调用了res.json()尝试发送JSON格式响应,第二次发送响应头时被Express拦截触发报错
同时因为produce_xml是异步逻辑,你直接将它的返回值作为json_results_in属性传入res.render时,XML请求还未完成,模板拿到的json_results_in实际是undefined,等到异步回调执行时,响应已经发送完毕。
代码存在的缺陷
- 同一请求重复发送响应,违反HTTP协议单请求单响应的规则
- 异步逻辑使用错误,没有等待异步请求返回结果就执行渲染操作
get_json.js中引入了express模块但全程未使用,属于冗余引入xml2js.parseString的解析错误没有捕获传递,解析失败时会静默出错- 异步请求发生错误时仅打印控制台,没有给客户端返回错误响应,会导致请求超时
res.json()方法本身会自动序列化JS对象为JSON字符串,额外套JSON.stringify属于多余操作,会导致返回结果被二次序列化
修复方案
根据你的业务需求选择对应场景的修复代码:
场景1:该接口仅需要返回JSON数据,不需要渲染页面
main.js 路由修正
app.get('/json_results', (req, res, next) => { // 请提前定义url变量为你要请求的XML数据源地址 getJson.produce_xml(url, function (err, data) { if (err) { return res.status(500).json({error: err.message}); } // res.json会自动序列化对象,无需手动调用JSON.stringify res.json(data); }); });
get_json.js 修正
// 删掉冗余的express引入 var https = require('https'); /** PARSE XML TO JSON */ var parsedtext = require('xml2js').parseString; function xmlToJson(url, callback) { var req = https.get(url, function(res) { var currentXml = ''; res.on('data', function(chunk) { currentXml += chunk; }) res.on('error', function(err) { callback(err, null); }) res.on('timeout', function(err) { callback(err, null); }) res.on('end', function() { // 捕获xml解析错误并传递 parsedtext(currentXml, function(err, result) { if (err) return callback(err, null); callback(null, result); }) }) }); // 捕获请求层面的错误,比如DNS解析失败、连接被拒绝等 req.on('error', function(err) { callback(err, null); }) } module.exports.produce_xml = xmlToJson
场景2:需要渲染json_results模板,将解析结果传入模板展示
main.js 路由修正
app.get('/json_results', (req, res, next) => { getJson.produce_xml(url, function (err, data) { if (err) { // 可根据自己的业务逻辑渲染错误页面 return res.status(500).send('请求失败:' + err.message); } // 拿到异步结果后再执行渲染 res.render('json_results', { title: 'NEWS TODAY', json_results_in: data }); }); });
get_json.js的修正逻辑和场景1一致。
注意:请确保代码中使用的url变量已提前定义为有效的XML数据源地址,否则会触发变量未定义错误。
内容的提问来源于stack exchange,提问作者Ray
相关产品推荐
相关产品推荐

