superagent是nodejs里一個非常方便的客戶端請求代理模塊(類似python之中的request模塊)當(dāng)你想處理get,post,put,delete,head請求時,你就應(yīng)該想起該用它了。
SuperAgent
superagent 是一個輕量的,漸進式的ajax api,可讀性好,學(xué)習(xí)曲線低,內(nèi)部依賴nodejs原生的請求api,適用于nodejs環(huán)境下.
一個簡單的post請求,并設(shè)置請求頭信息的例子
request
.post('/api/pet')
.send({ name: 'Manny', species: 'cat' })
.set('X-API-Key', 'foobar')
.set('Accept', 'application/json')
.end(function(res){
if (res.ok) {
alert('yay got ' + JSON.stringify(res.body));
} else {
alert('Oh no! error ' + res.text);
}
});
這個鏈接文檔,是用Mocha’s文檔自動輸出的,下面提供了這個測試文檔對應(yīng)的源文件
請求基礎(chǔ)
一個請求的初始化可以用請求對象里合適的方法來執(zhí)行,然后調(diào)用end()來發(fā)送請求,下面是一個簡單的get請求。
request
.get(''http://example.com/search'')
.end(function(res){ });
請求方法也可以通過參數(shù)傳遞:
request('GET', '/search').end(callback);
delete,head,post,put和別的http動作都可以使用,來換個方法看看:
request
.head('/favicon.ico')
.end(function(res){ });
delete是一個特列,因為它是系統(tǒng)保留的關(guān)鍵字,所以應(yīng)該用.del()這個名字:
request
.del('/user/1')
.end(function(res){ });
http請求默認的方法為get,所以就像你看到的,下面的這個例子也是可用的:
request('/search', function(res){ });
設(shè)置頭字段
設(shè)置頭字段非常簡單,只需調(diào)用.set()方法,傳遞一個名稱和值就行:
request
.get('/search')
.set('API-Key', 'foobar')
.set('Accept', 'application/json')
.end(callback);
你也可以直接傳遞一個對象進去,這樣一次就可以修改多個頭字段:
request
.get('/search')
.set({ 'API-Key': 'foobar', Accept: 'application/json' })
.end(callback);
Get請求
當(dāng)使用get
請求傳遞查詢字符串的時候,用.query()方法,傳遞一個對象就可以,下面的代碼將產(chǎn)生一個/search?query=Manny&range=1..5&order=desc
請求:
request
.get('/search')
.query({ query: 'Manny', range: '1..5', order: 'desc' })
.end(function(res){ });
POST/PUT請求
一個典型的json post請求看起來就像下面的那樣,設(shè)置一個合適的Content-type
頭字段,然后寫入一些數(shù)據(jù),在這個例子里只是json字符串:
request
.post('/user')
.set('Content-Type', 'application/json')
.send('{"name":"tj","pet":"tobi"}') .end(callback)
因為json非常通用,所以就作為默認的Content-type,下面的例子跟上面的一樣:
request
.post('/user')
.send({ name: 'tj', pet: 'tobi' })
.end(callback)
或者調(diào)用多次.send()方法(所有請求都可以如此操作):
request
.post('/user')
.send({ name: 'tj' }) .send({ pet: 'tobi' }) .end(callback)
默認發(fā)送字符串,將設(shè)置Content-type為application/x-www-form-urlencoded,多次調(diào)用將會通過&來連接,這里的結(jié)果為name=tj&pet=tobi:
request
.post('/user')
.send('name=tj')
.send('pet=tobi')
.end(callback);
superagent的請求數(shù)據(jù)格式化是可以擴展的,不過默認支持form和json兩種格式,想發(fā)送數(shù)據(jù)以application/x-www-form-urlencoded類型的話,則可以簡單的調(diào)用.type()方法傳遞form參數(shù)就行,這里默認是json,下面的請求將會發(fā)送postname=tj&pet=tobi內(nèi)容:
request
.post('/user')
.type('form')
.send({ name: 'tj' })
.send({ pet: 'tobi' })
.end(callback)
注意:form是form-data和urlencoded的別名,為了向后兼容
設(shè)置Content-Type
常見的方案是使用.set()方法:
request
.post('/user')
.set('Content-Type', 'application/json')
一個簡便的方法是調(diào)用.type()方法,傳遞一個規(guī)范的MIME名稱,包括type/subtype,或者一個簡單的后綴就像xml,json,png這樣,例如:
request
.post('/user')
.type('application/json')
request
.post('/user')
.type('json')
request
.post('/user')
.type('png')
設(shè)置接受類型
跟.type()簡便方法一樣,這里也可以調(diào)用.accept()方法來設(shè)置接受類型,這個值將會被request.types所引用,支持傳遞一個規(guī)范的MIME名稱,包括type/subtype,或者一個簡單的后綴就像xml,json,png這樣,例如:
request
.get('/user')
.accept('application/json')
request
.get('/user')
.accept('json')
request
.get('/user')
.accept('png')
查詢字符串
當(dāng)用.send(obj)方法來發(fā)送一個post請求,并且希望傳遞一些查詢字符串,可以調(diào)用.query()方法,比如向?format=json&dest=/login發(fā)送post請求:
request
.post('/')
.query({ format: 'json' })
.query({ dest: '/login' })
.send({ post: 'data', here: 'wahoo' })
.end(callback);
解析響應(yīng)內(nèi)容
superagent會解析一些常用的格式給請求者,當(dāng)前支持application/x-www-form-urlencoded,application/json,multipart/form-data.
JSON/Urlencoded
res.body是解析后的內(nèi)容對象,比如一個請求響應(yīng)'{"user":{"name":"tobi"}}'
字符串,res.body.user.name將會返回tobi,同樣的,x-www-form-urlencoded
格式的user[name]=tobi解析完的值,也是一樣的.
Multipart
nodejs客戶端通過Formidable模塊來支持multipart/form-data類型,當(dāng)解析一個multipart響應(yīng)時,res.files屬性就可以用.假設(shè)一個請求響應(yīng)下面的數(shù)據(jù):
--whoop
Content-Disposition: attachment;
name="image";
filename="tobi.png"
Content-Type: image/png
... data here ...
--whoop
Content-Disposition: form-data;
name="name"
Content-Type: text/plain
Tobi
--whoop--
你將可以獲取到res.body.name名為’Tobi’,res.files.image為一個file對象,包括一個磁盤文件路徑,文件名稱,還有其它的文件屬性。
響應(yīng)屬性
響應(yīng)一般會提供很多有用的標識以及屬性,都在response對象里,按照respone.text,解析后的response.body,頭字段,一些標識的順序來排列。
Response text
res.text包含未解析前的響應(yīng)內(nèi)容,一般只在mime類型能夠匹配text/,json,x-www-form-urlencoding的情況下,默認為nodejs客戶端提供,這是為了節(jié)省內(nèi)存.因為當(dāng)響應(yīng)以文件或者圖片大內(nèi)容的情況下影響性能。
Response body
跟請求數(shù)據(jù)自動序列化一樣,響應(yīng)數(shù)據(jù)也會自動的解析,當(dāng)為一個Content-Type
定義一個解析器后,就能自動解析,默認解析包含application/json和application/x-www-form-urlencoded,可以通過訪問res.body來訪問解析對象。
Response header fields
res.header包含解析之后的響應(yīng)頭數(shù)據(jù),鍵值都是node處理成小寫字母形式,比如res.header['content-length'].
Response Content-Type
Content-Type響應(yīng)頭字段是一個特列,服務(wù)器提供res.type來訪問它,默認res.charset是空的,如果有的話,則自動填充,例如Content-Type值為text/html; charset=utf8,則res.type為text/html,res.charst為utf8.
Response status
響應(yīng)狀態(tài)標識可以用來判斷請求是否成功,除此之外,可以用superagent來構(gòu)建理想的restful服務(wù)器,這些標識目前定義為:
var type = status / 100 | 0;
// status / class
res.status = status;
res.statusType = type;
// basics
res.info = 1 == type;
res.ok = 2 == type;
res.clientError = 4 == type;
res.serverError = 5 == type;
res.error = 4 == type || 5 == type;
// sugar
res.accepted = 202 == status;
res.noContent = 204 == status || 1223 == status;
res.badRequest = 400 == status;
res.unauthorized = 401 == status;
res.notAcceptable = 406 == status;
res.notFound = 404 == status;
res.forbidden = 403 == status;
中止請求
可以通過req.abort()來中止請求.
請求超時
可以通過req.timeout()來定義超時時間,然后當(dāng)超時錯誤發(fā)生時,為了區(qū)別于別的錯誤,err.timeout屬性被定義為超時時間,注意,當(dāng)超時錯誤發(fā)生后,后續(xù)的請求都會被重定向.不是每個請求.
基礎(chǔ)驗證
nodejs客戶端可以通過兩種方式來達到驗證的目的,第一個是傳遞一個像這樣的url,user:pass:
request
.get('http://tobi:learnboost[@local](/user/local)')
.end(callback);
第二種是調(diào)用.auth()方法:
request
.get('http://local')
.auth('tobo', 'learnboost')
.end(callback);
跟隨重定向
默認是向上跟隨5個重定向,不過可以通過調(diào)用.res.redirects(n)來設(shè)置個數(shù):
request .get('/some.png') .redirects(2) .end(callback);
管道數(shù)據(jù)
nodejs客戶端允許使用一個請求流來輸送數(shù)據(jù),比如請求一個文件作為輸出流:
var request = require('superagent') ,fs = require('fs');
var stream = fs.createReadStream('path/to/my.json');
var req = request.post('/somewhere');
req.type('json');
stream.pipe(req);
或者輸送一個響應(yīng)流到文件中:
var request = require('superagent') , fs = require('fs');
var stream = fs.createWriteStream('path/to/my.json');
var req = request.get('/some.json');
req.pipe(stream);
復(fù)合請求
superagent用來構(gòu)建復(fù)合請求非常不錯,提供了低級和高級的api方法.低級的api是使用多個部分來表現(xiàn)一個文件或者字段,.part()方法返回一個新的部分,提供了跟request本身相似的api方法.
var req = request.post('/upload');
req.part()
.set('Content-Type', 'image/png')
.set('Content-Disposition', 'attachment; filename="myimage.png"')
.write('some image data')
.write('some more image data');
req.part()
.set('Content-Disposition', 'form-data; name="name"')
.set('Content-Type', 'text/plain')
.write('tobi');
req.end(callback);
附加文件
上面提及的高級api方法,可以通過.attach(name, [path], [filename])和.field(name, value)這兩種形式來調(diào)用.添加多個附件也比較簡單,只需要給附件提供自定義的文件名稱,同樣的基礎(chǔ)名稱也要提供.
request
.post('/upload')
.attach('avatar', 'path/to/tobi.png', 'user.png')
.attach('image', 'path/to/loki.png')
.attach('file', 'path/to/jane.png')
.end(callback);
字段值
跟html的字段很像,你可以調(diào)用.field(name,value)方法來設(shè)置字段,假設(shè)你想上傳一個圖片的時候帶上自己的名稱和郵箱,那么你可以像下面寫的那樣:
request
.post('/upload')
.field('user[name]', 'Tobi')
.field('user[email]', 'tobi[@learnboost](/user/learnboost).com')
.attach('image', 'path/to/tobi.png')
.end(callback);
壓縮
nodejs客戶端本身就提供了壓縮響應(yīng)內(nèi)容,所以你不需要做任何其它事情.
緩沖響應(yīng)
為了強迫緩沖res.text這樣的響應(yīng)內(nèi)容,可以調(diào)用req.buffer()方法,想取消默認的文本緩沖響應(yīng)像text/plain,text/html這樣的,可以調(diào)用req.buffer(false)方法.
當(dāng)緩沖res.buffered標識提供了,那么就可以在一個回調(diào)函數(shù)里處理緩沖和沒緩沖的響應(yīng).
跨域資源共享
.withCredentials()方法可以激活發(fā)送原始cookie的能力,不過只有在Access-Control-Allow-Origin不是一個通配符(*),并且Access-Control-Allow-Credentials為’true’的情況下才行.
request
.get('http://localhost:4001/')
.withCredentials()
.end(function(res){
assert(200 == res.status);
assert('tobi' == res.text); next();
})
異常處理
當(dāng)發(fā)送錯誤時,superagent首先會檢查回調(diào)函數(shù)的參數(shù)數(shù)量,當(dāng)err參數(shù)提供的話,參數(shù)就是兩個,如下:
request
.post('/upload')
.attach('image', 'path/to/tobi.png')
.end(function(err, res){ });
``
當(dāng)省略了回調(diào)函數(shù),或者回調(diào)只有一個參數(shù)的話,可以添加error事件的處理.
```js
request
.post('/upload')
.attach('image', 'path/to/tobi.png')
.on('error', handle)
.end(function(res){ });
注意:superagent默認情況下,對響應(yīng)4xx和5xx的認為不是錯誤,例如當(dāng)響應(yīng)返回一個500或者403的時候,這些狀態(tài)信息可以通過res.error,res.status和其它的響應(yīng)屬性來查看,但是沒有任務(wù)的錯誤對象會傳遞到回調(diào)函數(shù)里或者emit一個error事件.正常的error事件只會發(fā)生在網(wǎng)絡(luò)錯誤,解析錯誤等.當(dāng)產(chǎn)生一個4xx或者5xx的http錯誤響應(yīng),res.error提供了一個錯誤信息的對象,你可以通過檢查這個來做某些事情.
if (res.error) { alert('oh no ' + res.error.message);}
else { alert('got ' + res.status + ' response');}