发布于 2017-05-30 08:07:31 | 126 次阅读 | 评论: 0 | 来源: 网友投递
Node.js 服务器端的JavaScript
Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台, 用来方便地搭建快速的 易于扩展的网络应用· Node.js 借助事件驱动, 非阻塞I/O 模型变得轻量和高效, 非常适合 运行在分布式设备 的 数据密集型 的实时应用
Request是一个Node.jsNPM模块,它是一个HTTP客户端,使用简单功能确十分强大。我们可以用它来实现HTTP响应流的转接、模拟Form表单提交、支持HTTP认证、OAuth登录、自定义请求头等。下面我们来对这个模块做一个完整的介绍:
1. 安装及简单使用
安装request模块:
npm install request
Request设计为用最简单的方法发送HTTP请求,它还支持HTTPS请求和自动重定向跟踪:
var request = require('request');
request('http://www.baidu.com', function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body) // IT笔录主页的HTML
}
})
引用request模块后,就可以能通过request()方法来发送HTTP请求,在不指定请求选项option时,默认为GET。在上面请求中,对URLhttp://www.baidu.com
会301重定向到http://www.baidu.com。而Request会自动跟踪URL重定向请求,默认支持10次重定向跟踪。
2. 流(stream)操作
Node.js原生HTTP模块实现了对HTTP请求和响应对象的流操作,Request同样支持基于流的操作。
如,可以将任何响应流通过pipe转接到一个文件流:
request('http://google.com/doodle.png').pipe(fs.createWriteStream('doodle.png'))
同样,可以将一个读取的文件流转接到PUT或POST请求中。这个方法会自动检查文件扩展名,并设置一个与文件扩展名对应的content-type(当该请求头未设置时):
fs.createReadStream('file.json').pipe(request.put('http://mysite.com/obj.json'))
Request也支持pipe到它自己。这样操作时,content-type和content-length将被传递到其后的PUT请求中:
request.get('http://google.com/img.png').pipe(request.put('http://mysite.com/img.png'))
与原生HTTP客户端一样,Request在收到请求响应时会发送一个'response'。事件回调函数中会包含一个response参数,它是一个http.IncomingMessage实例:
request
.get('http://google.com/img.png')
.on('response', function(response) {
console.log(response.statusCode) // 200
console.log(response.headers['content-type']) // 'image/png'
})
.pipe(request.put('http://mysite.com/img.png'))
当请求发生错误时,可以简单的通过监听error事件来处理:
request
.get('http://mysite.com/doodle.png')
.on('error', function(err) {
console.log(err)
})
.pipe(fs.createWriteStream('doodle.png'))
发挥一个想象:
http.createServer(function (req, resp) {
if (req.url === '/doodle.png') {
if (req.method === 'PUT') {
req.pipe(request.put('http://mysite.com/doodle.png'))
} else if (req.method === 'GET' || req.method === 'HEAD') {
request.get('http://mysite.com/doodle.png').pipe(resp)
}
}
})
也可以使用pipe()方法将一个http.ServerRequest实例转换到一个http.ServerResponse。HTTP请求方法、请求头、请求体数据会被发送:
http.createServer(function (req, resp) {
if (req.url === '/doodle.png') {
var x = request('http://mysite.com/doodle.png')
req.pipe(x)
x.pipe(resp)
}
})
通过pipe()返回的目标流,在Nodev0.5.x+版本中,可以写到一行:
req.pipe(request('http://mysite.com/doodle.png')).pipe(resp)
而所有这些,没有一个新功能会与原功能有冲突,只是对其进行了扩展。还可以使用HTTP代理,请求会被自动重定向并跟踪:
var r = request.defaults({'proxy':'http://localproxy.com'})
http.createServer(function (req, resp) {
if (req.url === '/doodle.png') {
r.get('http://google.com/doodle.png').pipe(resp)
}
})
3. Form表单
request支付application/x-www-form-urlencoded 和 multipart/form-data 编码的form 上传。multipart/related会引用multipartAPI。
application/x-www-form-urlencoded (URL编码的Form)
URL编码的Form很简单:
request.post('http://service.com/upload', {form:{key:'value'}})
// or
request.post('http://service.com/upload').form({key:'value'})
// or
request.post({url:'http://service.com/upload', form: {key:'value'}}, function(err,httpResponse,body){ /* ... */ })
multipart/form-data (Multipart Form 上传)
对于multipart/form-dataFrom文件上传,Request使用了form-data处理。大多数情况,可以通过formData选项添加上传文件:
var formData = {
// 键-值对简单值
my_field: 'my_value',
// 使用 Buffers 添加数据
my_buffer: new Buffer([1, 2, 3]),
// 使用 Streams 添加数据
my_file: fs.createReadStream(__dirname + '/unicycle.jpg'),
// 通过数组添加 multiple 值
attachments: [
fs.createReadStream(__dirname + '/attachment1.jpg'),
fs.createReadStream(__dirname + '/attachment2.jpg')
],
// 添加可选的 meta-data 使用: {value: DATA, options: OPTIONS}
// 对于一些流类型,需要提供手工添加 "file"-关联
// 详细查看 `form-data` : https://github.com/form-data/form-data
custom_file: {
value: fs.createReadStream('/dev/urandom'),
options: {
filename: 'topsecret.jpg',
contentType: 'image/jpg'
}
}
};
request.post({url:'http://service.com/upload', formData: formData}, function optionalCallback(err, httpResponse, body) {
if (err) {
return console.error('upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
});
在一些更加高级的使用中,可以通过其自身的如r.form()来访问Form数据:
// NOTE: Advanced use-case, for normal use see 'formData' usage above
var r = request.post('http://service.com/upload', function optionalCallback(err, httpResponse, body) {...})
var form = r.form();
form.append('my_field', 'my_value');
form.append('my_buffer', new Buffer([1, 2, 3]));
form.append('custom_file', fs.createReadStream(__dirname + '/unicycle.jpg'), {filename: 'unicycle.jpg'});
multipart/related
在一些不同的HTTP实现中,需要在multipart/related的之前、之后或前后同时添加一个newline/CRLF(通过multipart选项)。特别是在.NET WebAPI 4.0中,需要将preambleCRLF设置为true:
request({
method: 'PUT',
preambleCRLF: true,
postambleCRLF: true,
uri: 'http://service.com/upload',
multipart: [
{
'content-type': 'application/json',
body: JSON.stringify({foo: 'bar', _attachments: {'message.txt': {follows: true, length: 18, 'content_type': 'text/plain' }}})
},
{ body: 'I am an attachment' },
{ body: fs.createReadStream('image.png') }
],
// alternatively pass an object containing additional options
multipart: {
chunked: false,
data: [
{
'content-type': 'application/json',
body: JSON.stringify({foo: 'bar', _attachments: {'message.txt': {follows: true, length: 18, 'content_type': 'text/plain' }}})
},
{ body: 'I am an attachment' }
]
}
},
function (error, response, body) {
if (error) {
return console.error('upload failed:', error);
}
console.log('Upload successful! Server responded with:', body);
})
4. HTTP认证
在一些HTTP请求中,需要对请求对象进行身份验证。Request提供了多种身份验证方式:
request.get('http://some.server.com/').auth('username', 'password', false);
// or
request.get('http://some.server.com/', {
'auth': {
'user': 'username',
'pass': 'password',
'sendImmediately': false
}
});
// or
request.get('http://some.server.com/').auth(null, null, true, 'bearerToken');
// or
request.get('http://some.server.com/', {
'auth': {
'bearer': 'bearerToken'
}
});
当使用auth选项进,其可包含以下值:
而对于最终调用的auth(username, password, sendImmediately, bearer)方法来说,sendImmediately默认为true,这会导致一个 basic 或 bearer 认证头会被发送。如果sendImmediately设置为false,request会在收到401状态后尝试使用一个合适的认证头。
注意,也可以基于RFC 1738标准,在URL中添加认证信息。简单的是使用方式是在主机的@符号前添加user:password:
var username = 'username',
password = 'password',
url = 'http://' + username + ':' + password + '@some.server.com';
request({url: url}, function (error, response, body) {
// Do more stuff with 'body' here
});
5. 自定义HTTP头
如果需要设置自定义的HTTP请求头,如:User-Agent,可以通过options对象设置。
var request = require('request');
var options = {
url: 'https://api.github.com/repos/request/request',
headers: {
'User-Agent': 'request'
}
};
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body);
console.log(info.stargazers_count + " Stars");
console.log(info.forks_count + " Forks");
}
}
request(options, callback);
6. OAuth签名
Request支持OAuth 1.0。其默认使用的签名算法为 HMAC-SHA1:
// OAuth1.0 - 3-legged server side flow (Twitter example)
// step 1
var qs = require('querystring')
, oauth =
{ callback: 'http://mysite.com/callback/'
, consumer_key: CONSUMER_KEY
, consumer_secret: CONSUMER_SECRET
}
, url = 'https://api.twitter.com/oauth/request_token'
;
request.post({url:url, oauth:oauth}, function (e, r, body) {
// Ideally, you would take the body in the response
// and construct a URL that a user clicks on (like a sign in button).
// The verifier is only available in the response after a user has
// verified with twitter that they are authorizing your app.
// step 2
var req_data = qs.parse(body)
var uri = 'https://api.twitter.com/oauth/authenticate'
+ '?' + qs.stringify({oauth_token: req_data.oauth_token})
// redirect the user to the authorize uri
// step 3
// after the user is redirected back to your server
var auth_data = qs.parse(body)
, oauth =
{ consumer_key: CONSUMER_KEY
, consumer_secret: CONSUMER_SECRET
, token: auth_data.oauth_token
, token_secret: req_data.oauth_token_secret
, verifier: auth_data.oauth_verifier
}
, url = 'https://api.twitter.com/oauth/access_token'
;
request.post({url:url, oauth:oauth}, function (e, r, body) {
// ready to make signed requests on behalf of the user
var perm_data = qs.parse(body)
, oauth =
{ consumer_key: CONSUMER_KEY
, consumer_secret: CONSUMER_SECRET
, token: perm_data.oauth_token
, token_secret: perm_data.oauth_token_secret
}
, url = 'https://api.twitter.com/1.1/users/show.json'
, qs =
{ screen_name: perm_data.screen_name
, user_id: perm_data.user_id
}
;
request.get({url:url, oauth:oauth, qs:qs, json:true}, function (e, r, user) {
console.log(user)
})
})
})
使用RSA-SHA1 签名时,可传入如下一个OAuth对象:
而使用PLAINTEXT 签名,可传入如下一个OAuth对象:
7. 代理
如果指定proxy(代理)选项后,所有的请求(及其后的重定向)都会连接到该代理服务器。
如果终端是一个httpsURL,代理会使用CONNECT请求连接到代理服务器。
首先会生成类似如下一个请求:
HTTP/1.1 CONNECT endpoint-server.com:80
Host: proxy-server.com
User-Agent: whatever user agent you specify
然后建立一个到endpoint-server(终端服务器)的80端口的TCP连接,并按如下返回响应:
HTTP/1.1 200 OK
默认情况下,当代理使用http进行通讯时,request会简单的生成一个标准的http代理请求。如,会像如下这样生成一个请求:
HTTP/1.1 GET http://endpoint-server.com/some-url
Host: proxy-server.com
Other-Headers: all go here
request body or whatever
通过proxyHeaderExclusiveList选项可以明确指定一些代理头,默认会按如下方式设置:
accept
accept-charset
accept-encoding
accept-language
accept-ranges
cache-control
content-encoding
content-language
content-length
content-location
content-md5
content-range
content-type
connection
date
expect
max-forwards
pragma
proxy-authorization
referer
te
transfer-encoding
user-agent
via
8. UNIX域套接字
request支持到UNIX域套接字的请求:
/* Pattern */ 'http://unix:SOCKET:PATH'
/* Example */ request.get('http://unix:/absolute/path/to/unix.socket:/request/path')
注意:SOCKET应该是一个到文件系统根目录的绝对路径。
9. TLS/SSL协议
对于使用了TLS/SSL等安全协议的请求,可以使用相关选项如cert、key、passphrase也可以使用agentOptions选项甚至使用https.globalAgent.options来设置:
var fs = require('fs')
, path = require('path')
, certFile = path.resolve(__dirname, 'ssl/client.crt')
, keyFile = path.resolve(__dirname, 'ssl/client.key')
, caFile = path.resolve(__dirname, 'ssl/ca.cert.pem')
, request = require('request');
var options = {
url: 'https://api.some-server.com/',
cert: fs.readFileSync(certFile),
key: fs.readFileSync(keyFile),
passphrase: 'password',
ca: fs.readFileSync(caFile)
}
};
request.get(options);
使用options.agentOptions
在下面示例中,我们调用一个需要API,它需要客户端SSL证书(PEM格式)用密码保护私钥(PEM格式)并禁用SSLv3协议:
var fs = require('fs')
, path = require('path')
, certFile = path.resolve(__dirname, 'ssl/client.crt')
, keyFile = path.resolve(__dirname, 'ssl/client.key')
, request = require('request');
var options = {
url: 'https://api.some-server.com/',
agentOptions: {
cert: fs.readFileSync(certFile),
key: fs.readFileSync(keyFile),
// 或使用 `pfx` 属性替换 `cert` 和 `key`使用私钥时,证书和CA证书在 PFX 或 PKCS12 格式的文件中:
// pfx: fs.readFileSync(pfxFilePath),
passphrase: 'password',
securityOptions: 'SSL_OP_NO_SSLv3'
}
};
request.get(options);
如果强制使用SSLv3,则通过secureProtocol指定:
request.get({
url: 'https://api.some-server.com/',
agentOptions: {
secureProtocol: 'SSLv3_method'
}
});
10. 对HAR 1.2的支持
options.har属性会重写url。method, qs, headers, form, formData, body, json的值,当request.postData.params[].fileName的值不存在时,会从硬盘文件构建 multipart 数据
当HAC 请求匹配到指定规则时会执行验证检查,如果未匹配到则会跳过:
var request = require('request')
request({
// 将会忽略
method: 'GET',
uri: 'http://www.google.com',
// HTTP 存档请求对象
har: {
url: 'http://www.mockbin.com/har',
method: 'POST',
headers: [
{
name: 'content-type',
value: 'application/x-www-form-urlencoded'
}
],
postData: {
mimeType: 'application/x-www-form-urlencoded',
params: [
{
name: 'foo',
value: 'bar'
},
{
name: 'hello',
value: 'world'
}
]
}
}
})
// 一个 POST 请求会发送到 http://www.mockbin.com
// 其请求体编码为 application/x-www-form-urlencoded,发送内容:
// foo=bar&hello=world
11. option所有可用参数
request()的请求格式有如下两种形式:
request(options, callback);
// 或
request(url, options, callback);
当使用request.put()、request.post()等便捷方法进行请求时,同样有如下两种形式:
request.METHOD(options, callback);
// 或
request.METHOD(url, options, callback);
options表示请求选项,其中只有>url/uri是必须参数,其它都是可选值。下面是一些常用选项:
查询字符串相关选项:
请求体相关选项:
认证相关选项:
重定向相关选项:
编码/压缩相关选项:
代理相关选项:
本地代理选项:
HAR相关选项:
12. 便捷方法
Request还可以使用以HTTP方法命名的便捷方法。
request.defaults(options)
返回一个正常请求API的包装器,其默认值为所传递的options选项。
示例:
// 使用 baseRequest() 进行请求是会设置一个 'x-token' 请求头
var baseRequest = request.defaults({
headers: {'x-token': 'my-token'}
})
// 使用 specialRequest() 进行请求时,会包含一个在 baseRequest 中设置的 'x-token' 请求头
// 还会有一个 'special' 请求头
var specialRequest = baseRequest.defaults({
headers: {special: 'special value'}
})
request.put
与request()方法相同,但默认method: "PUT"
request.put(url)
request.patch
与request()方法相同,但默认method: "PATCH"
request.patch(url)
request.post
与request()方法相同,但默认method: "POST"
request.post(url)
request.head
与request()方法相同,但默认method: "HEAD"
request.head(url)
request.del / request.delete
与request()方法相同,但默认method: "DELETE"
request.del(url)
request.delete(url)
request.get
与request()方法相同
request.get(url)
request.cookie
创建一个新Cookie
request.cookie('key1=value1')
request.jar
创建一个新Cookie Jar
request.jar()
注:Cookie Jar用于保存所访问网站的Cookie信息
13. 使用示例
var request = require('request')
, rand = Math.floor(Math.random()*100000000).toString()
;
request(
{ method: 'PUT'
, uri: 'http://mikeal.iriscouch.com/testjs/' + rand
, multipart:
[ { 'content-type': 'application/json'
, body: JSON.stringify({foo: 'bar', _attachments: {'message.txt': {follows: true, length: 18, 'content_type': 'text/plain' }}})
}
, { body: 'I am an attachment' }
]
}
, function (error, response, body) {
if(response.statusCode == 201){
console.log('document saved as: http://mikeal.iriscouch.com/testjs/'+ rand)
} else {
console.log('error: '+ response.statusCode)
console.log(body)
}
}
)
为了保持向后兼容,响应压缩默认不会启用。要访问gzip压缩的响应,需要将gzip选项设置为true。这样数据体会通过request自动解压缩,而响应的对象将未包含压缩数据。
var request = require('request')
request(
{ method: 'GET'
, uri: 'http://www.google.com'
, gzip: true
}
, function (error, response, body) {
// body 是解压缩后的 response 响应体
console.log('server encoded the data as: ' + (response.headers['content-encoding'] || 'identity'))
console.log('the decoded data is: ' + body)
}
).on('data', function(data) {
// 收到的是解压缩后的数据
console.log('decoded chunk: ' + data)
})
.on('response', function(response) {
// 未修改 http.IncomingMessage object
response.on('data', function(data) {
// 收到的是压缩数据
console.log('received ' + data.length + ' bytes of compressed data')
})
})
Cookie默认是未启用的,可以通过将jar选项设置为true来启用Cookie:
var request = request.defaults({jar: true})
request('http://www.google.com', function () {
request('http://images.google.com')
})
使用自定义的Cookie Jar,可以将jar选项设置为一个request.jar()实例:
var j = request.jar()
var request = request.defaults({jar:j})
request('http://www.google.com', function () {
request('http://images.google.com')
})
或
var j = request.jar();
var cookie = request.cookie('key1=value1');
var url = 'http://www.google.com';
j.setCookie(cookie, url);
request({url: url, jar: j}, function () {
request('http://images.google.com')
})
使用自定义的Cookie存储,可以做为request.jar()的参数传入:
var FileCookieStore = require('tough-cookie-filestore');
// 这时 'cookies.json' 文件必须已经存在
var j = request.jar(new FileCookieStore('cookies.json'));
request = request.defaults({ jar : j })
request('http://www.google.com', function() {
request('http://images.google.com')
}
Cookie存储必须是一个tough-cookie且必须支持同步操作。
在请求完成后,检查你的Cookie Jar:
var j = request.jar()
request({url: 'http://www.google.com', jar: j}, function () {
var cookie_string = j.getCookieString(url); // "key1=value1; key2=value2; ..."
var cookies = j.getCookies(url);
// [{key: 'key1', value: 'value1', domain: "www.google.com", ...}, ...]
})
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持phperz。