NodeJS 网络服务 http server
http 服务端概览
创建 server
几行代码搞定
var http = require('http');
var requestListener = function(req, res){
res.end('ok');
};
var server = http.createServer(requestListener);
// var server = new http.Server(requestListener); 跟上面是等价的
server.listen(3000);
获取请求方信息
HTTP 版本、HTTP method、headers、url
var http = require('http');
var server = http.createServer(function(req, res){
console.log('客户端请求 url:' + req.url);
console.log('http 版本:' + req.httpVersion);
console.log('http 请求方法:' + req.method);
res.end('ok');
});
server.listen(3000);
效果如下:
客户端请求 url:/hello
http 版本:1.1
http 请求方法:GET
http headers:{"host":"127.0.0.1:3000","connection":"keep-alive","cache-control":"max-age=0","upgrade-insecure-requests":"1","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36","accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8","accept-encoding":"gzip, deflate, sdch, br","accept-language":"zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4"}
获取 get 请求参数
var http = require('http');
var url = require('url');
var querystring = require('querystring');
var server = http.createServer(function(req, res){
var urlObj = url.parse(req.url);
var query = urlObj.query;
var queryObj = querystring.parse(query);
console.log( JSON.stringify(queryObj) );
res.end('ok');
});
server.listen(3000);
运行如下命令
curl http://127.0.0.1:3000/hello\?nick\=chyingp\&hello\=world
服务端输出如下
{"nick":"chyingp","hello":"world"}
获取 post 请求参数
代码如下
var http = require('http');
var url = require('url');
var querystring = require('querystring');
var server = http.createServer(function(req, res){
var body = '';
req.on('data', function(thunk){
body += thunk;
});
req.on('end', function(){
console.log( 'post body is: ' + body );
res.end('ok');
});
});
server.listen(3000);
通过 curl 构造极简 post 请求
curl -d 'nick=casper&hello=world' http://127.0.0.1:3000
服务端打印如下。注意,在 post 请求中,不同的 Content-type
,post body 有不小差异,感兴趣的同学可以自己试下。
post body is: nick=casper&hello=world
比如本例中的 post 请求,HTTP 报文大概如下
POST / HTTP/1.1
Host: 127.0.0.1:3000
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
nick=casper&hello=world
枯燥的事件
首先,我们来看下有哪些事件
checkContinue、checkExpectation、clientError、close、connect、connection、request、upgrade
error
var http = require('http');
var PORT = 3000;
var noop = function(){};
var svr = http.createServer(noop);
var anotherSvr = http.createServer(noop);
anotherSvr.on('error', function(e){
console.error('出错啦!' + e.message);
});
svr.listen(PORT, function(){
anotherSvr.listen(PORT);
});
运行代码,输出如下
出错啦!listen EADDRINUSE :::3000
connect vs connection
两者差别非常大,虽然字眼看着有点像。
- connect:当客户端的 HTTP method 为 connect 时触发。
- connection:当 TCP 连接建立时触发,大部分时候可以忽略这个事件(目测模块内部自己用到而已)。此外,可以通过 req.connection 来获取这个 socket(从 nodejs 源码来看,req.socket、req.connection 都指向了这个 socket)。此外,socket 上的 readable 事件不会触发(具体原因请看模块内部实现,反正我是还没研究)
大部分时候都不会用到,除非你要开发 HTTP 代理。当客户端发起 connect 请求时触发(注意绕过了 requestListener)
var http = require('http');
var PORT = 3000;
var server = http.createServer(function(req, res){
res.end('ok');
});
// 注意:发起 connect 请求的例子在 ./httpServerEventConnectClient.js 里
server.on('connect', function(req, socket, head){
console.log('connect 事件触发');
socket.end(); // 反正我就只想举个例子,没打算正经处理。。。
});
server.listen(PORT);
request
当有新的连接到来时触发。那跟 connection 有什么区别呢?
好了, keep-alive
闪亮登场!在持久化连接的情况下,多个 request 可能对应的是 一个 connection。
先来看下没有 keep-alive
的场景
var http = require('http');
var PORT = 3000;
var requestIndex = 0;
var connectionIndex = 0;
var server = http.createServer(function(req, res){
res.end('ok');
});
server.on('request', function(req, res){
requestIndex++;
console.log('request event: 第'+ requestIndex +'个请求!');
});
server.on('connection', function(req, res){
connectionIndex++;
console.log('connection event: 第'+ connectionIndex +'个请求!');
});
server.listen(PORT);
通过 curl 连续发送 3 个请求,看下效果
for i in `seq 1 3`; do curl http://127.0.0.1:3000; done
服务端输出如下
connection event: 第 1 个请求!
request event: 第 1 个请求!
connection event: 第 2 个请求!
request event: 第 2 个请求!
connection event: 第 3 个请求!
request event: 第 3 个请求!
然后,再来看下有 keep-alive
的场景。用 postman 构造包含 keep-alive 的请求,最终的 HTTP 请求报文如下
GET / HTTP/1.1
Host: 127.0.0.1:3000
Connection: keep-alive
Cache-Control: no-cache
Postman-Token: 6027fda7-f936-d3ac-e54f-dafcbf5e58ff
连续发送 3 个请求,服务端打印日志如下
connection event: 第 1 个请求!
request event: 第 1 个请求!
request event: 第 2 个请求!
request event: 第 3 个请求!
不常用接口
server.close([callback]);
关闭服务器。其实就是 (new net.Server()).close(),停止接受新的连接。 已经连接上的请求会继续处理,当所有连接结束的时候,server 正式关闭,并抛出 close 事件。 一般提供了 callback,就不用监听 close; 监听了 close,就不用添加 callback。
其他 server.listen()
其实除了 server.listen(PORT) 这种监听方式外,还有以下几种相对不那么常用的监听方式。用到的时候看看文档就行了。
server.listen(handle[, callback]):监听本地文件描述符(fd)(windows 不支持),或者 server,或者 socket server.listen(path[, callback]):监听本地 socket,创建一个 UNIX socket server 。 server.listen([port][, hostname][, backlog][, callback])
网络超时 server.setTimeout(msecs, callback)
设置网络连接的超时时间。当超过 msecs 没有响应时,网络就会自动断开。
如果传了 callback,那么当 timeout 发生时,就会将 timeout 的 socket 作为参数传给 callback。
注意,一般情况下超时的 socket 会自动销毁。但当你传了 callback 后,你就需要手动 end 或者 destroy 这个 socket。
不常用属性
server.listening:是否在监听连接 server.timeout:设置超时时间(毫秒),注意,修改这个值,只会对新建立的连接产生影响。此外,将 timeout 设置为 0,就会禁用自动超时行为。(目测不推荐) server.maxHeadersCount:客户端最多传送的 header 数量,默认是 1000,如果设置为 0,则没有限制。(问题:如果超过 1000 怎么办??)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: NodeJS 网络服务 http res
下一篇: 彻底找到 Tomcat 启动速度慢的元凶
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论