Node.js API详解之 http (下)

http模块提供了创建服务端与客户端的接口,
通过 const http = require(‘http’); 的方式引用http模块
本章介绍客户端部分,也就是请求发起端的api.

目录:

http.ClientRequest 类

http.Agent 类

http.request(options[, callback])

说明:

Node.js 为每台服务器维护多个连接来进行 HTTP 请求。 该函数允许显式地发出请求。
options:可以是一个对象、或字符串、或 URL 对象。 如果 options 是一个字符串,它会被自动使用 url.parse() 解析。
如果它是一个 URL 对象, 它会被默认转换成一个 options 对象。
callback:callback 参数会作为单次监听器被添加到 ‘response’ 事件
http.request() 返回一个 http.ClientRequest 类的实例。

demo:

const http = require('http');

const postData = JSON.stringify({ msg : 'Hello World!'});

const options = {
	protocol:'http:',		//使用的协议。默认为 http:
	host:'127.0.0.1',		//请求发送至的服务器的域名或 IP 地址。默认为 localhost
  	hostname: '127.0.0.1',		// host 的别名。为了支持 url.parse(),hostname 优先于 host。
  	family:'4',	//当解析 host 和 hostname 时使用的 IP 地址族。 有效值是 4 或 6。当未指定时,则同时使用 IP v4 和 v6。		
  	port: 8061,//远程服务器的端口。默认为 80。
  	localAddress:'',//为网络连接绑定的本地接口。
  	socketPath:'',// Unix 域 Socket(使用 host:port 或 socketPath)。
  	method:'POST',//指定 HTTP 请求方法的字符串。默认为 'GET'
  	path: '/user',//请求的路径。默认为 '/'。 应包括查询字符串(如有的话)。如 '/index.html?page=12'。 
  	headers: {//包含请求头的对象。
  	  'Content-Type': 'application/x-www-form-urlencoded',
  	  'Content-Length': Buffer.byteLength(postData)
  	},
  	auth:'xiaoqiang:123123',//基本身份验证,如 'user:password' 用来计算 Authorization 请求头。
  	agent:false,//控制 Agent 的行为。 可能的值有Agent对象,false,undefined
  	timeout:1000,// 指定 socket 超时的毫秒数。 它设置了 socket 等待连接的超时时间。
  	createConnection:()=>{}//当不使用 agent 选项时,为请求创建一个 socket 或流。 这可以用于避免仅仅创建一个自定义的 Agent 类来覆盖默认的 createConnection 函数
};


const req = http.request(options, (res) => {
  	console.log(`状态码: ${res.statusCode}`);
  	console.log(`响应头: ${JSON.stringify(res.headers)}`);
});

//如果请求过程中遇到任何错误,则在返回的请求对象中会触发 'error' 事件。 
//对于所有的 'error' 事件,如果没有注册监听器,则抛出错误。
req.on('error', (e) => {
  	console.error(`请求遇到问题: ${e.message}`);
});

// 写入数据到请求主体
req.write(postData);
req.end(); 		//使用 http.request() 必须调用 req.end() 来表明请求的结束,即使没有数据被写入请求主体。

http.get(options[, callback])

说明:

因为大多数请求都是 GET 请求且不带请求主体,所以 Node.js 提供了该便捷方法。
该方法与 http.request() 唯一的区别是它设置 method 为 GET 且自动调用 req.end()。
options:接受与 http.request() 相同的 options 参数
callback:callback 被调用时只传入一个参数,该参数是 http.IncomingMessage 的一个实例。

demo:

const http = require('http');
http.get('http://127.0.0.1:8061/index', (res) => {
  	const { statusCode } = res;

  	if (statusCode !== 200) {
 		console.error('请求失败。\n' + `状态码: ${statusCode}`);
    	// 消耗响应数据以释放内存
    	res.resume();
    	return;
  	}

  	res.setEncoding('utf8');
  	let rawData = '';
  	res.on('data', (chunk) => { rawData += chunk; });
  	res.on('end', () => {
      	console.log(rawData);
  	});
}).on('error', (e) => {
 	console.error(`错误: ${e.message}`);
});

http.ClientRequest 类

说明:

该对象在 http.request() 内部被创建并返回。
它表示着一个正在处理的请求,其请求头已进入队列。 请求头仍可使用 setHeader()、getHeader() 和 removeHeader() API 进行修改。
实际的请求头会与第一个数据块一起发送或当调用 request.end() 时发送
要获取响应,需为请求对象添加一个 ‘response’ 事件监听。 当响应头被接收到时,请求对象会触发 ‘response’ 事件 。
‘ response’ 事件被执行时带有一个参数,该参数是一个 http.IncomingMessage 实例。
如果没有添加 ‘response’ 事件处理函数,则响应会被整个丢弃。 如果添加了 ‘response’ 事件处理函数,则必须消耗完响应对象的数据,
可通过调用 response.read()、或添加一个 ‘data’ 事件处理函数、或调用 .resume() 方法。
数据被消耗完时会触发 ‘end’ 事件。 在数据被读取完之前会消耗内存,可能会造成 ‘process out of memory’ 错误。
注意:Node.js 不会检查 Content-Length 与已传输的请求主体的长度是否相等。

response 事件

说明:

当请求的响应被接收到时触发。 该事件只触发一次。

request.write(chunk[, encoding][, callback])

说明:

使用该方法发送请求主体。
chunk:要发送的字符串或Buffer
encoding:仅当 chunk 是一个字符串时才有效。默认为 ‘utf8’。
callback:当数据块被刷新时调用

request.end([data[, encoding]][, callback])

说明:

结束发送请求, 如果部分请求主体还未被发送,则会更新它们到流中。
如果请求是分块的,则会发送终止字符 ‘0\r\n\r\n’。
data:如果指定了 data,则相当于调用 request.write(data, encoding) 之后再调用 request.end(callback)。
callback:当请求流结束时会被调用。

demo:

const http = require('http');

const postData = JSON.stringify({ msg : 'Hello World!'});

const options = {	
  	hostname: '127.0.0.1',		
  	port: 8061,
  	method:'POST',//指定 HTTP 请求方法的字符串。默认为 'GET'
  	path: '/user',//请求的路径。默认为 '/'。 应包括查询字符串(如有的话)。如 '/index.html?page=12'。 
  	headers: {//包含请求头的对象。
  	  'Content-Type': 'application/x-www-form-urlencoded',
  	  'Content-Length': Buffer.byteLength(postData)
  	}
};

const req = http.request(options);

req.on('response', (res) => {
	let rawData = '';
	res.setEncoding('utf8');

  	console.log(`状态码: ${res.statusCode}`);
  	console.log(`响应头: ${JSON.stringify(res.headers)}`);
  	
  	res.on('data', (chunk) => { rawData += chunk; });
  	res.on('end', () => {
      	console.log(`正文:${rawData}`);
  	});
});

// 写入数据到请求主体
req.write(postData);
req.end();

// 输出:
// 状态码: 200
// 响应头: {"date":"Thu, 28 Dec 2017 07:04:00 GMT","connection":"close","content-length":"7"}
// 正文:success

request.abort()

说明:

标记请求为终止。 调用该方法将使响应中剩余的数据被丢弃且 socket 被销毁。

request.aborted

说明:

如果请求已被终止,则该属性的值为请求被终止的时间,从 1 January 1970 00:00:00 UTC 到现在的毫秒数。

abort 事件

说明:

当请求已被客户端终止时触发。 该事件仅在首次调用 abort() 时触发

demo:

req.on('abort', () => {
	console.log(req.aborted);
});
req.abort();
// 输出:
// 1514447494949

request.setHeader(name, value)

说明:

为 headers 对象设置一个单一的 header 值。如果该 header 已经存在了,则将会被替换。
这里使用一个字符串数组来设置有相同名称的多个 headers。

demo:

req.setHeader('Content-Type','application/json');
req.setHeader('Set-Cookie', ['type=ninja', 'language=javascript']);

request.getHeader(name)

说明:

读出请求头,注意:参数name是大小写敏感的

request.removeHeader(name)

说明:

移除一个已经在 headers 对象里面的 header。

demo:

req.setHeader('Content-Type','application/json');
req.setHeader('Set-Cookie', ['type=ninja', 'language=javascript']);

console.log(req.getHeader('Content-Type'));
//application/json

req.removeHeader('Content-Type');

console.log(req.getHeader('Content-Type'));		
//undefined

request.flushHeaders()

说明:

刷新请求头。Node.js 通常会缓存请求头直到 request.end() 被调用或第一块请求数据被写入。
如果想提前开始请求,不等待第一个数据块写入,执行此方法。

demo:

req.setHeader('Content-Type','application/json');
req.setHeader('Set-Cookie', ['type=ninja', 'language=javascript']);

console.log(req.getHeader('Content-Type'));
//application/json

req.flushHeaders();

req.removeHeader('Content-Type');

//throw new Error('Can\'t remove headers after they are sent');

request.socket, request.connection

说明:

引用底层socket。 通常用户不想访问此属性。在response.end()之后,该属性为null。
也可以通过request.connection来访问socket。

socket 事件

说明:

当 socket 被分配到请求后触发。

connect 事件

说明:

每当服务器响应 CONNECT 请求时触发。
如果该事件未被监听,则接收到 CONNECT 方法的客户端会关闭连接。

demo:

const req = http.request(options);
req.end();

req.on('connect', (res, socket, head) => {
    console.log('已连接!');
});

upgrade 事件

说明:

每当服务器响应 upgrade 请求时触发。
如果该事件未被监听,则接收到 upgrade 请求头的客户端会关闭连接

demo:

srv.on('upgrade', (req, socket, head) => {  });

continue 事件

说明:

当服务器发送了一个 100 Continue 的 HTTP 响应时触发,通常是因为请求包含 Expect: 100-continue。
这是客户端将要发送请求主体的指令。

timeout 事件

说明:

当底层 socket 超时的时候触发。该方法只会通知空闲的 socket。请求必须手动停止。

request.setSocketKeepAlive([enable][, initialDelay])

说明:

一旦 socket 被分配给请求且已连接,socket.setKeepAlive() 会被调用。

request.setTimeout(timeout[, callback])

说明:

一旦 socket 被分配给请求且已连接,socket.setTimeout() 会被调用。

request.setNoDelay([noDelay])

说明:

一旦 socket 被分配给请求且已连接,socket.setNoDelay() 会被调用。

http.Agent 类

说明:

Agent 负责为 HTTP 客户端管理连接的持续与复用。它为一个给定的主机与端口维护着一个等待请求的队列,
且为每个请求重复使用一个单一的 socket 连接直到队列为空,此时 socket 会被销毁或被放入一个连接池中,
在连接池中等待被有着相同主机与端口的请求再次使用。 是否被销毁或被放入连接池取决于 keepAlive 选项。
当 Agent 实例不再被使用时,建议 destroy() 它,因为未被使用的 socket 也会消耗操作系统资源。

new Agent([options])

说明:

实例化一个Agent
options:Agent的配置选项。有以下字段:
keepAlive:保持 socket 可用,即使没有请求,以便它们可被将来的请求使用而无需重新建立一个 TCP 连接。默认为 false。
keepAliveMsecs:使用了 keepAlive 选项时,该选项指定 TCP Keep-Alive 数据包的 初始延迟。
当 keepAlive 选项为 false 或 undefined 时,该选项无效。 默认为 1000。
maxSockets:每个主机允许的最大 socket 数量。 默认为 Infinity。
maxFreeSockets:在空闲状态下允许打开的最大 socket 数量。 仅当 keepAlive 为 true 时才有效。 默认为 256。

demo:

const http = require('http');

const postData = JSON.stringify({ msg : 'Hello World!'});

const options = {	
  	hostname: '127.0.0.1',		
  	port: 8061,
  	method:'POST',//指定 HTTP 请求方法的字符串。默认为 'GET'
  	path: '/user',//请求的路径。默认为 '/'。 应包括查询字符串(如有的话)。如 '/index.html?page=12'。 
  	headers: {//包含请求头的对象。
  	  'Content-Type': 'application/x-www-form-urlencoded',
  	  'Content-Length': Buffer.byteLength(postData)
  	}
};
const keepAliveAgent = new http.Agent({ keepAlive: true });
options.agent = keepAliveAgent;
const req = http.request(options);

req.on('response', (res) => {
	let rawData = '';
	res.setEncoding('utf8');

  	console.log(`状态码: ${res.statusCode}`);
  	console.log(`响应头: ${JSON.stringify(res.headers)}`);
  	
  	res.on('data', (chunk) => { rawData += chunk; });
  	res.on('end', () => {
      	console.log(`正文:${rawData}`);
  	});
});

// 写入数据到请求主体
req.write(postData);
req.end();

agent.createConnection(options[, callback])

说明:

创建一个用于 HTTP 请求的 socket 或流。
socket 或流可以通过以下两种方式获取:从该函数返回,或传入 callback。
options: 包含连接详情的选项。查看 net.createConnection() 了解选项的格式。
callback: callback 有 (err, stream) 参数。

agent.keepSocketAlive(socket)

说明:

在 socket 被请求分离的时候调用, 可能被代理持续使用.

agent.reuseSocket(socket, request)

说明:

由于 keep-alive 选项被保持持久化, 在 socket 附加到 request 时调用. 默认行为是:
socket.ref();

agent.destroy()

说明:

销毁当前正被代理使用的任何 socket。
通常不需要这么做。 但是如果使用的代理启用了 keepAlive,则当确定它不再被使用时,最好显式地关闭代理。
否则,在服务器终止它们之前,socket 可能还会长时间保持打开。

agent.getName(options)

说明:

为请求选项的集合获取一个唯一的名称,用来判断一个连接是否可以被复用。
对于 HTTP 代理,返回 host:port:localAddress 或 host:port:localAddress:family。
对于 HTTPS 代理,名称会包含 CA、证书、密码、以及其他 HTTPS/TLS 特有的用于判断 socket 复用性的选项。

agent.freeSockets

说明:

返回一个对象,包含当前正在等待被启用了 keepAlive 的代理使用的 socket 数组。
不要修改该属性。

agent.maxFreeSockets

说明:

默认为 256。 对于已启用 keepAlive 的代理,该属性可设置要保留的空闲 socket 的最大数量。

agent.maxSockets

说明:

默认为不限制。 该属性可设置代理为每个来源打开的并发 socket 的最大数量。
来源是 agent.getName() 的返回值。

agent.requests

说明:

返回一个对象,包含还未被分配到 socket 的请求队列。
不要修改。

agent.sockets

说明:

返回一个对象,包含当前正被代理使用的 socket 数组。
不要修改。

http.globalAgent

说明:

Agent的全局实例,作为所有HTTP客户端请求的默认Agent。