node使⽤request请求的⽅法
近期使⽤node做服务端渲染,作为中间层需要请求后端接⼝,需要封装服务端的请求,接下来来了解下如何使⽤ request。
基本使⽤
const request = require('request')
引⼊这个包就可以开始使⽤了,最简单的使⽤⽅式就是 request(url) 就可以想指定的地址发起⼀个 get 请求。从这⾥我们可以看出 request 暴露出来的就是⼀个函数。其实它内部的结构如下
function request (uri, options, callback) {
if (typeof uri === 'undefined') {
throw new Error('undefined is not a valid uri or options object.')
}
var params = initParams(uri, options, callback)
if (hod === 'HEAD' && paramsHaveRequestBody(params)) {
throw new Error('HTTP HEAD requests MUST NOT include a request body.')
}
return new request.Request(params)
}
可以看出它默认接收三个函数,并且第⼀个参数值必须存在,request的传参⽅式也有很多种,本⾝做了很多⽀持的处理,来看看它⽀持的传参数⽅式。
⼊参格式
url 必填,可以单独放在第⼀个参数,或者作为 option 的属性之⼀。其他都是可选。
// ⽅式⼀
request(url,options,callback)
// ⽅式⼆
let options = {
url // 必填
}
request(options,callback)
简写⽅式
// ⽅式⼀
<(url,options,callback)
// ⽅式⼆
let options = {
url // 必填
}
<(options,callback)
// ⽅式⼀
request.post(url,options,callback)
// ⽅式⼆
let options = {
url
}
request.post(options,callback)
为啥 request ⽀持这么多种传参数⽅式。来看看它内部的实现⽅式
源码
下⾯代码可以看出,request 对参数类型进⾏类型判断来采⽤不同的合并⽅式,最终 return 的params要求就是要包含url请求地址。
function initParams (uri, options, callback) {
// 处理没有传 options 的情况
if (typeof options === 'function') {
callback = options
}
var params = {}
if (typeof options === 'object') {
extend(params, options, {uri: uri})
// 传递的 url 最终也会被合并到 pramas 上
// 并且如果你在 options 传递了 uri 会被第⼀参数覆盖,优先级以第⼀个⼊参uri为准
} else if (typeof uri === 'string') {
extend(params, {uri: uri})
} else {
// 处理第⼀参数不是url的情况
extend(params, uri)
}
params.callback = callback || params.callback
return params
}
常⽤字段
request(options,callback) 提供 baseUrl 来统⼀设置域名部分及公共部分。
// 定义了 baseUrl 后只需要传递接⼝ api 即可
function fetchPost(path,params){
return new Promise( (resolve,reject)=>{
request.post(path,{
baseUrl:"localhost:9000/react/",
},function(err, httpResponse, body){
if(err){
reject(err)
}else{
resolve(body)
}
})
})
}
// 使⽤,只传递了接⼝部分最终会拼接成 localhost:9000/react/c-request
<('/c-request',async ctx=>{
let res = await fetchPost('request-header',{value:1,name:'dd'})
ctx.body = res
})
reqeust 不同数据类型的请求及 debug
为了模拟node服务端请求后端的场景,启动两个node服务,⼀个作为请求⽅模拟(中间层),另⼀个作为后端。另外通过postman 来发起客户端的请求。关于数据的验证可以使⽤ vscode 的 debug 功能也可以开启 pm2 log 来验证请求的参数。
接下来看下 post 不同格式的请求⽅式的设置,不同与 axios , fetch 。request对于不同请求⽅式的数据
接收的字段是不同的。可以通过 body、form、formData 来接收。get的请求都是通过 application/x-www-form-urlencoded 格式来传递数据的,所以这⾥暂不举例。
application/x-www-form-urlencoded
通过forms字段来接收⼊参,⽅法如下,直接将传⼊的参数对象传递给 form 即可。
function fetchPost(path,params){
return new Promise( (resolve,reject)=>{
request.debug = true
request.post(path,{
form:params
react router如何使用},function(err, httpResponse, body){
if(err){
reject(err)
}else{
resolve(body)
}
})
})
}
request 有个debug 模式,通过request.debug = true开启,为了查看debug信息,使⽤pm2 start app.js --watch启动项⽬,然后pm2 log来查看debug信息。红⾊代表中间层的log,绿⾊代表后端的log
使⽤ node debug 查看接收到的 request.body是后端接收到的值 request.header是接收到的请求 content-type
都会将⼊参传递到 body 这个字段上
form-data ⽂件上传
通过formData来传递⽂件,代码如下:使⽤ fs.createReadStream 去拿到中间层的⽂件,然后通过 formData ⽅式发送给后端。
function fetchPost(path,params){
return new Promise( (resolve,reject)=>{
let formData = {
ateReadStream(__dirname+'/../static/images/icon-arrow.png')
}
request.debug = true
request.post(path,{
formData
},function(err, httpResponse, body){
if(err){
reject(err)
}else{
resolve(body)
}
})
})
}
可以看到后端接收到到 content-type 为 multipart/form-data ,我们并没有⼿动的去设置请求的 content-type 会⾃动添加上。
下⾯代码会将接收到到⽂件流写⼊到后端local。可以看到 icon-arrow.jpg 已经成功的从中间层发送到后端
application/json
将参数通过 body 传递,并且设置 json为ture,那么请求时会⾃动将 content-type 设置为 application/json 并且将传递给 body 的对象转义为 JSON
function fetchPost(path,params){
return new Promise( (resolve,reject)=>{
request.debug = true
console.log('*'.repeat(40));
request.post(path,{
baseUrl:"localhost:9000/react/",
body:params,
json:true
},function(err, httpResponse, body){
if(err){
reject(err)
}else{
resolve(body)
}
})
})
}
header
request.post(path,{
form:params,
headers:{
// 'content-type':'application/json',
// ... 任意其他字段
name:'dd',
agent:'request'
}
})
通过id号来区分当前进程,
可以通过 pm2 start app.js --name 请求端来定义进程名称