模块/http.res.md
http模块四剑客之一的res,应该都不陌生了。一个web服务程序,接受到来自客户端的http请求后,向客户端返回正确的响应内容,这就是res的职责。
返回的内容包括:状态代码/状态描述信息、响应头部、响应主体。下文会举几个简单的例子。
var http = require('http');
var server = http.createServer(function(req, res){
res.end('ok');
});
server.listen(3000);
在下面的例子中,我们同时设置了 状态代码/状态描述信息、响应头部、响应主体,就是这么简单。
var http = require('http');
// 设置状态码、状态描述信息、响应主体
var server = http.createServer(function(req, res){
res.writeHead(200, 'ok', {
'Content-Type': 'text/plain'
});
res.end('hello');
});
server.listen(3000);
res提供了 res.writeHead()、res.statusCode/res.statusMessage 来实现这个目的。
举例,如果想要设置 200/ok ,可以
res.writeHead(200, 'ok');
也可以
res.statusCode = 200;
res.statusMessage = 'ok';
两者差不多,差异点在于
res提供了 res.writeHead()、response.setHeader() 来实现响应头部的设置。
举例,比如想把 Content-Type 设置为 text-plain,那么可以
// 方法一
res.writeHead(200, 'ok', {
'Content-Type': 'text-plain'
});
// 方法二
res.setHeader('Content-Type', 'text-plain');
两者的差异点在哪里呢?
关于第2点差异,这里举个例子。下面代码,最终的 Content-Type 为 text/plain。
var http = require('http');
var server = http.createServer(function(req, res){
res.setHeader('Content-Type', 'text/html');
res.writeHead(200, 'ok', {
'Content-Type': 'text/plain'
});
res.end('hello');
});
server.listen(3000);
而下面的例子,则直接报错。报错信息为 Error: Can't set headers after they are sent.。
var http = require('http');
var server = http.createServer(function(req, res){
res.writeHead(200, 'ok', {
'Content-Type': 'text/plain'
});
res.setHeader('Content-Type', 'text/html');
res.end('hello');
});
server.listen(3000);
增、删、改、查 是配套的。下面分别举例说明下,例子太简单就直接上代码了。
// 增
res.setHeader('Content-Type', 'text/plain');
// 删
res.removeHeader('Content-Type');
// 改
res.setHeader('Content-Type', 'text/plain');
res.setHeader('Content-Type', 'text/html'); // 覆盖
// 查
res.getHeader('content-type');
其中略显不同的是 res.getHeader(name),name 用的是小写,返回值没做特殊处理。
res.setHeader('Content-Type', 'TEXT/HTML');
console.log( res.getHeader('content-type') ); // TEXT/HTML
res.setHeader('Content-Type', 'text/plain');
console.log( res.getHeader('content-type') ); // text/plain
此外,还有不那么常用的:
主要用到 res.write() 以及 res.end() 两个方法。
res.write() API的信息量略大,建议看下官方文档。
使用上没什么难度,只是有些注意事项:
Returns true if the entire data was flushed successfully to the kernel buffer. Returns false if all or part of the data was queued in user memory. 'drain' will be emitted when the buffer is free again.
掌握了 res.write() 的话,res.end() 就很简单了。res.end() 的用处是告诉nodejs,header、body都给你了,这次响应就到这里吧。
有点像个语法糖,可以看成下面两个调用的组合。至于callback,当响应传递结束后触发。
res.write(data, encoding);
res.end()
参考这里:http://stackoverflow.com/questions/6258210/how-can-i-output-data-before-i-end-the-response
也就是说,除了nodejs的特性,还需要了解 HTTP协议、浏览器的具体实现。(细思极恐)
如果是 text/html
var http = require('http');
http.createServer(function(req, res) {
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.write('hello');
setTimeout(function() {
res.write(' world!');
res.end();
}, 2000);
}).listen(3000);
如果是 text/plain
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {
'Content-Type': 'text/plain; charset=utf-8',
'X-Content-Type-Options': 'nosniff'
});
res.write('hello');
setTimeout(function(){
res.write('world');
res.end()
}, 2000);
}).listen(3000);
失败例子
var http = require('http');
var server = http.createServer(function(req, res){
res.writeHead(200, 'ok', {
'Content-Type': 'text/html'
});
res.write('hello');
setTimeout(function(){
res.write('world');
res.end();
}, 2000);
});
server.listen(3000);
接口:response.setTimeout(msecs, callback)
关于 timeout 事件的说明,同样是言简意赅(WTF),话少信息量大,最好来个demo TODO
If no 'timeout' listener is added to the request, the response, or the server, then sockets are destroyed when they time out. If you assign a handler on the request, the response, or the server's 'timeout' events, then it is your responsibility to handle timed out sockets.
How can I output data before I end the response? http://stackoverflow.com/questions/6258210/how-can-i-output-data-before-i-end-the-response
8.2.3 Use of the 100 (Continue) Status http://greenbytes.de/tech/webdav/rfc2616.html#use.of.the.100.status