# HTTP 通信过程

# 创建一个 HTTP 服务器

const http = require('http');

const server = http.createServer((request, response) => {
  // magic happens here!
});

http.createServer([options][, requestListener]) 创建一个 http.Server 实例. 接收一个函数作为 'request' 事件的监听函数.

http.Server 实例 同时也是一个 events.EventEmitter 对象实例

上面的代码等价于:

const http = require('http');
const server = http.createServer();
server.on('request', (request, response) => {
  // the same kind of magic happens here!
});

当服务器接收到 http 请求的时候, 就会在请求处理函数中去处理 request, response 对象, 而为了监听到客户端发过来的请求, 就需要用到 listen 方法.

listen 方法用于监听一个具体的服务器端口, 以来接收从客户端发到指定端口的请求.

server.listen(3000);

# 请求方法, URL 和 请求头部

http.IncomingMessage 文档

在处理请求的时候, 我们最先要看的一般就是 请求方法 和 请求 URL.

从客户端发过来的请求对象里面包含着这些属性, 可以很方便的获取到.

请求对象是 http.IncomingMessage 实例

req.headers 例子

{ host: 'localhost:3001',
  'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:61.0) Gecko/20100101 Firefox/61.0',
  accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'accept-language': 'zh-CN,en-GB;q=0.7,en;q=0.3',
  'accept-encoding': 'gzip, deflate',
  connection: 'keep-alive',
  'upgrade-insecure-requests': '1',
  'cache-control': 'max-age=0' }

# 请求体

当收到 POSTPUT 请求的时候, 请求体就尤为重要了.

请求对象实现了 ReadableStream 接口, 所有的流都是 EventEmitter 的实例 (IncomingMessage 继承自 EventEmitter)

请求对象可以监听流的 dataend 事件, data 事件向其回调函数传递一个 Buffer 类型的参数. 之后在 end 事件的回调函数中将所有数据 字符串化.

let body = [];
request.on('data', (chunk) => {
  body.push(chunk);
}).on('end', () => {
  body = Buffer.concat(body).toString();
  // at this point, `body` has the entire request body stored in it as a string
});

# 错误处理

因为 请求对象是一个 EventEmitter, 所以它可以接受 error 事件.
如果不为 error 事件设置一个监听函数的话, 如果错误发生, 服务器就会崩停的.

request.on('error', (err) => {
  console.log(err);
});

最好向客户端返回一个 http 回应.

# 服务器做出回应

收到客户端发过来的请求后, 服务器就要向客户端返回一个响应了.

响应对象 是 http.ServerResponse 实例, 实现了 WritableStream 接口.

# 状态码, 响应头, 响应头

响应状态码 默认是 200.

如果想设置的话, 可以通过 statusCode 属性.

response.statusCode = 404;

通过 setHeader 方法可以设置 响应头

response.setHeader('Content-Type', 'application/json');
response.setHeader('X-Powered-By', 'bacon');

通过 writeHead, 可以同时设置这两个:

response.writeHead(200, {
  'Content-Type': 'application/json',
  'X-Powered-By': 'bacon'
});

因为 响应对象 实现了 WriteableStrem 接口, 我们可以手动去写响应体

response.write('<html>');
response.write('<body>');
response.write('<h1>Hello, World!</h1>');
response.write('</body>');
response.write('</html>');
response.end();

end() 函数可以用来在流的最后添加数据, 上面代码也可以写成:

response.end('<html><body><h1>Hello, World!</h1></body></html>');

# 错误处理

response.on('error', (err) => {
    console.error(err);
});
上次更新: 7/4/2020, 4:14:54 AM