node中的几个常用核心模块的api返回的都是eventEmitter的实例,也就是说都继承了on和emit方法,用以监听事件并触发回调来处理事件。
http模块处理网络请求通常是创建一个server实例:
1 const server = http.createServer((request, response) => { 2 // magic happens here! 3 });
它是以下代码的简写:
1 const server = http.createServer(); 2 server.on('request', (request, response) => { 3 // the same kind of magic happens here! 4 });
其中request和response是传入回调的参数,他们是包含了处理请求所需的属性和方法的对象,便于我们完成操作。
request是一个http.IncomingMessage类的实例,带有 Readable Stream接口(方便我们操作流数据),常用的属性有.headers[Obj]、.url[str]、.method[str]
1 const { method, url,headers } = request;
详见:https://nodejs.org/api/http.html#http_class_http_incomingmessage
当遇到POST或PUT的请求时,我们需要获取报文实体主体的数据,既然request带有Readable Stream接口,我们可以调用这个api获取:
1 const http = require('http'); 2 3 http.createServer((request, response) => { 4 const { headers, method, url } = request; 5 let body = []; 6 request.on('error', (err) => { 7 console.error(err); 8 }).on('data', (chunk) => { 9 body.push(chunk); 10 }).on('end', () => { 11 body = Buffer.concat(body).toString(); 12 // At this point, we have the headers, method, url and body, and can now 13 // do whatever we need to in order to respond to this request. 14 }); 15 }).listen(8080); // Activates this server, listening on port 8080.
response是一个http.ServerResponse实例,也是一个WritableStream实例。带有方便我们设置响应头和响应主体的api。
response.statusCode = 404;
1 response.setHeader('Content-Type', 'application/json'); 2 response.setHeader('X-Powered-By', 'bacon');
也可以一次性完成上面代码:
1 response.writeHead(200, { 2 'Content-Type': 'application/json', 3 'X-Powered-By': 'bacon' 4 });
官方文档强调要先写好响应头的statusCode和headers再写主体,毕竟响应头比响应主体先到达。
1 response.write('<html>'); 2 response.write('<body>'); 3 response.write('<h1>Hello, World!</h1>'); 4 response.write('</body>'); 5 response.write('</html>'); 6 response.end();
上面的write是WritableStream的api方便我们写响应主体,当然也可以直接写在end()里面:
1 response.end('<html><body><h1>Hello, World!</h1></body></html>');
在官方文档中给过一个echo例子,将request的内容通过pipe()方法尽数写入response作为响应。
1 http.createServer((request, response) => { 2 if (request.method === 'GET' && request.url === '/echo') { 3 request.pipe(response); 4 } else { 5 response.statusCode = 404; 6 response.end(); 7 } 8 }).listen(8080);
这里,ReadableStream的pipe()方法在写入完成后,会触发它自身的end事件,然后默认地调用Writablestream的end()方法,即相当于自动调用了response.end();另外,pipe()方法也会返回对目标writerable的引用,便于链式调用。https://nodejs.org/api/stream.html#stream_class_stream_writable