各位大神晚上好,这个问题是我使用rrestjs时候偶然发现的,网上也没查阅到相关资料,写了如下的issues提交给老吴了,以下是发现这个问题的被坑、寻坑、填坑的过程。
当我实现了旁路业务和核心业务分离之后,随之而来的就遇到一些列的麻烦和问题,程序会莫名其妙的告诉我
Error: Can't set headers after they are sent.
,通过一个案例测试出来,案例如下:
var http = require('http');
var rrest = require('rrestjs');
var server = http.createServer(function(req,res){
if(true){
res.send('123');
}
res.send('321');
}).listen(80);
当我打开浏览器输入
127.0.0.1
的时候,页面是显示123
,但是后台报错
http.js:644
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (http.js:644:11)
at RestZlib.send (D:\projects\eclipse\node_modules\rrestjs\lib\RestZlib.js:20:7)
at Gzip.onEnd (zlib.js:153:5)
at Gzip.EventEmitter.emit (events.js:85:17)
at zlib.js:349:10
at Zlib.callback (zlib.js:439:13)
这样的错误我在原生的写法里没有遇到过,于是我开始用原生写法如下案例测试
var http = require('http');
var server = http.createServer(function(req,res){
if(true){
res.write(JSON.stringify({a:123}));
res.end();
}
res.write(JSON.stringify({a:321}));
res.end();
}).listen(80);
浏览器显示
{"a":123}
好的,这没报错,这不是我所希望的,我反而希望他报错,于是我看了下之前的报错提示Can't set headers after they are sent.
,翻译过来就是他们已经发送,您无法设置headers
,难道发送后就不能设置headers了吗?于是我改进了原生代码,是这样的
var http = require('http');
var server = http.createServer(function(req,res){
if(true){
res.writeHeader(200, {'Content-Type':'text/javascript;charset=UTF-8'})
res.write(JSON.stringify({a:123}));
res.end();
}
res.writeHeader(200, {'Content-Type':'text/javascript;charset=UTF-8'})
res.write(JSON.stringify({a:321}));
res.end();
}).listen(80);
结果是浏览器依然有显示后台也没报错,我很不甘心,于是我想,是不是要在发送后,设置点不一样的headers呢?继续改进原生的代码
var http = require('http');
var server = http.createServer(function(req,res){
if(true){
res.writeHeader(200, {'Content-Type':'text/javascript;charset=UTF-8'})
res.write(JSON.stringify({a:123}));
res.end();
}
res.writeHead(200, {'Content-Length': 1024,'Content-Type': 'text/plain;charset=GBK' });
res.write(JSON.stringify({a:321}));
res.end();
}).listen(80);
node似乎很智能啊,这样依然没有报错,我依然不甘心,我把关键字锁定在了
set
上,我想我是不是该调用setHeader方法呢,于是我这样
var http = require('http');
var server = http.createServer(function(req,res){
if(true){
res.setHeader('Content-Type','text/javascript;charset=UTF-8');
res.write(JSON.stringify({a:123}));
res.end();
}
res.setHeader('Content-Length',1024);
res.setHeader('Content-Type','text/html;charset=GBK');
res.write(JSON.stringify({a:321}));
res.end();
}).listen(80);
好吧,其实我已经精疲力尽的写到这了,我真希望这个错误能重现,果然出现了,和rrestjs框架所报的错误一模一样,因此呢…… 我的建议就是将setHeader都替换为writeHeader,这样他不会报错,而且一旦发送出去req是不会重发(后面的依然会执行,但不会重发)。 另外我想知道setHeader和writeHead的本质区别
问题是已经发给老吴了,也发给大家看看,希望大家帮忙找找相关文案,迫切想知道这2个方法的本质区别(包括为什么writeHead重复设置不会报错,而setHeader会报错),小弟拜谢!
真心求解,各位大神飘过留言啊。。。
很好理解吧。。。http协议不是先发头的么。。。
从api上开,setHeader是可以多次设置http头部的,writeHeader只能设置一次,将状态吗,还有header一次性设置好。功能不同
大叔,你这个找问题的方式不对吧,错误提示: throw new Error(‘Can’t set headers after they are sent.’);
这不是告诉你headers 已经被sent过了嘛,你应该查一下send是否允许重复调用呢? 还写这么多测试代码,直接api不就完事了啊
http协议就是这样的, 一旦你开始发送html实体了, 你再setHeader一定会报错的, 人家都提示你了 无语…
- 楼主测试的方法不对,问题出在向客户端发送数据后,仍然尝试更改header,所以引发错误,与是用response.setHeader 还是 response.writeHead无关
- response.setHeader 与 response.writeHead的区别,通过查看文档与编码测试,发现如下区别:
- 前者只能设置单个头的信息,后者可以设置多个
- 后者可以设置状态消息与状态文本,前者待定(此处我不确定)
- 后者设置的信息将与前者设置的信息合并,一起被发送给客户端