Node擅长处理I/O操作,所以它不仅合适提供HTTP服务,也适合使用这些服务。接下来你将学习使用http模块和第三方模块执行和控制http请求。
在HTTP协议中,有两个重要的属性:URL和方法。最常见的是GET、POST方法,还有PUT等别的方法。
const http = require('http');
const options = {
host: 'localhost',
port: 1234,
path: '/'
}
http.get(options, (res) => {
console.log(res);
})
在上面这个例子中,使用TCP端口1234向主机名localhost和路径/执行GET请求(localhost:1234/)。回调函数会在服务器响应到达的时候处理响应对象。
http.get 是通用的 http.request 的快捷方式,其选项如下:
http.request 方法会返回一个 http.ClientRequest 对象,它是一个可写流,可以使用这个流发送数据,所发送的数据是请求主体数据的一部分,当完成向请求主体中写入数据时,要结束数据流来终止请求。
完整的请求,你可以这么写:
const http = require('http');
const options = {
host: 'localhost',
port: 1234,
path: '/',
method: 'POST'
}
// 发送请求,监听响应
const req = http.request(options, (response) => {
console.log(response.statusCode);
console.log(response.headers);
response.setEncoding('utf-8');
response.on('data', (chunk) => {
console.log('BODY : ' + chunk);
})
})
req.write('This is a request');
req.end();
http.request 返回ClientRequest对象,可以通过req.write()方法将请求主体写入该对象,可以传入一个经过编码的字符串,或者缓冲区。必须使用end()去结束请求,不然会被认为请求不完整,从而不会处理该请求。
如果服务器正常工作,会返回一个响应,客户端接收到响应触发response事件:
req.on('response', (res) => {
console.log(res);
})
响应对象是ClientResponse的一个实例,主要属性有:
响应主体并不会在请求的response事件发生时出现,而是需要监听data事件:
http.request(options, (response) => {
response.setEncoding('utf8');
response.on('data', (data) => {
console.log(data);
})
})
响应主题可以是一个缓冲区,但是如果指定了编码格式,那么就是一个编码字符串了。
HTTP响应是一个可读流,表示响应主体数据流。可以将一个可读流送入一个可写流中,例如一个HTTP请求或者一个文件:
const http = require('http');
const fs = require('fs');
const options = {
host: 'localhost',
port: 1234,
path: '/',
method: "GET"
}
const file = fs.createWriteStream('./test.text');
http.request(options, (res) => {
res.pipe(file);
}).end();
上面创建了一个可写文件流,并将响应体写入文件。
当响应到达,文件流打开,响应体写入;当响应主体结束的时候,文件流也结束,文件流被关闭。
在创建HTTP请求的时候,Node在内部使用了一个代理。
代理是Node中的一种实体,该实体用来给你创建请求,它负责维护一个套接字池,对指定的主机名和端口对,套接字池中包含已经被打开但是未被使用的连接。
当出现新的HTTP请求时,代理要求连接保持活跃状态;当请求结束,并且在套接字上没有额外的请求等待释放时,套接字就会被关闭,而不用手动关闭。
当创建了一个请求并选择了一个可用的套接字,或者为该请求创建了一个新的连接时,http.ClientRequest 会发射socket事件。在请求结束之后,套接字会在发射close事件或agentRemove事件时从套接字池中被删除。
Node的HTTP客户端非常强大,但是用起来很麻烦:
通过使用 request 模块可以简化操作。
使用npm在当前目录下安装该模块
npm install request
然后使用:
const r = require('request');
之后只需要提供URL和回调就可以创建请求了
request('localhost:1234', (error,res,body) => {
...
})
如果按上述代码发送请求,默认为GET请求吗,如果想要使用其他HTTP动词,例如post:request.put(url);
还可以用option对象来替代URL,可选参数可以查看官方文档。
const http = require('http');
const server = http.createServer();
// 监听请求
server.on("request", (req, res) => {
// 回送一个消息
const printBack = function () {
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.end(JSON.stringify({
URL: req.url,
method: req.method,
Headers: req.headers
}))
}
// 路由
switch (req.url) {
// 重定向
case '/redirect':
res.writeHead(301, { "Location": '/' })
res.end();
break;
// 打印请求体
case '/print/body':
req.setEncoding('utf8');
let body = "";
req.on('data', (data) => {
body += data;
});
// 结束之后,响应以发送body结束
req.on('end', () => {
res.end(JSON.stringify(body));
})
break;
// 默认
default:
printBack();
break;
}
})
server.listen(1234);
const request = require('request');
const inspect = require('util').inspect;
request.get('http://localhost:1234/print/body', (err, res, body) => {
if(err) {
throw err;
}
console.log(inspect({
err: err,
res: {
statusCode: res.statusCode
},
body: JSON.parse(body)
}))
})
request 的特性之一是它在默认情况下能够跟随重定向。可以用上面的代码来观察这个特征:
当请求路径为/redirect时,可以用301重定向响应码做出响应。可以用客户端来查看跟随上述URL的请求:
将请求路径修改为/redirect,可以在客户端看到返回信息中路径为/而不是/redirect。
如果你希望发生重定向的时候得到通知,可以把请求选项中的followRedirect设置为 false 。
const options = {
url: 'http://localhost:1234',
method: 'POST',
headers: {
'...': '...'
}
}
request(options, function(err, res, body){
...........
})
有时候需要在请求主体上发送一些数据,可以使用表单编码对请求体进行编码:
const body = {
a: 1,
b: 2
};
const options = {
url: '...',
form: body
// 还可以采用json编码,如下:
// json: body
}
请求返回的是一个客户端请求对象,可以将该对象传入可写流当中,甚至可以将请求对象传入另一个请求。
传入文件
request.get('...').pipe(fs.createWriteStream('...'));
传入另一个请求
request.get('...').pipe(request.post('...'));