在Node中构建HTTP服务非常容易:
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
HTTP
http的全称是超文本传输协议,构建在TCP之上,属于应用层协议。
HTTP报文示例:
第一部分,TCP的3次握手:
$ curl -v http://127.0.0.1:1337
* About to connect() to 127.0.0.1 port 1337 (#0)
* Trying 127.0.0.1...
* connected
* Connected to 127.0.0.1 (127.0.0.1) port 1337 (#0)
第二部分,客户端发送请求报文给服务器:
> GET / HTTP/1.1
> User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8r zlib/1.2.5
> Host: 127.0.0.1:1337 > Accept: */*
>
服务器响应,包括了响应头和响应体
< HTTP/1.1 200 OK
< Content-Type: text/plain
< Date: Sat, 06 Apr 2013 08:01:44 GMT
< Connection: keep-alive
< Transfer-Encoding: chunked
<
Hello World
这部分是结束会话的信息
* Connection #0 to host 127.0.0.1 left intact
* Closing connection #0
http模块
在Node中,HTTP服务继承自TCP服务器,它能够与多个客户端保持连接,由于其采用时间驱动的形式,并不为每一个连接创建额外的线程或者进程,保持很低的内存占用,所以能实现高并发。
http请求
> GET / HTTP/1.1
> User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8r zlib/1.2.5 2
> Host: 127.0.0.1:1337 > Accept: */*
>
第一行的GET / HTTP/1.1被解析之后会分解为如下属性:
1、req.method: GET
2、req.url: /
3、req.httpVersion: 1.1
HTTP请求对象和HTTP响应对象是相对比较底层的封装,现行的Web框架如Express都是在这两个对象的基础上进行高层封装完成的。
http响应
http响应封装了对底层连接的写操作,可以将其看作一个可写的流对象。它影响响应报文头部信息的API为res.setHeader()和res. writeHead()。
我们可以调用setHeader进行多次设置,但只有调用writeHead后,报头才会写入到连接中。
报文体的部分则是调用res.write和res.end方法实现,后者与前者的区别在于res.end会先调用write发送数据,然后发送信号告知服务器这次响应结束。
注意:报头是在报文体发送前发送的,一旦开始了数据的发送,res.setHeader()和res. writeHead()将不再生效。
HTTP客户端
var options = {
hostname: '127.0.0.1',
port: 1334,
path: '/',
method: 'GET'
};
var req = http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log(chunk);
});
});
req.end();