本文主要參考superagent的官方文檔,基本上就是它的翻譯。html
題外話,superagent真是一個不錯的nodejs模塊,推薦使用。node
前言json
superagent 是一個流行的nodejs第三方模塊,專一於處理服務端/客戶端的http請求。api
在nodejs中,咱們可使用內置的http等模塊來進行請求的發送、響應處理等操做,不過superagent提供了更加簡單、優雅的API,讓你在處理請求時更加方便。並且它很輕量,學習曲線平滑,內部其實就是對內置模塊的封裝。跨域
下面讓咱們先來看一個簡單的例子,大體的瞭解下request的基本用法,以及它和使用內置模塊的區別。服務器
var request = require('superagent'); var http = require('http') var queryString = require('queryString'); // 使用superagent request .post('/api/pet') .send({ name: 'Manny', species: 'cat' }) .set('X-API-Key', 'foobar') .set('Accept', 'application/json') .end(function(err, res){ if (res.ok) { alert('yay got ' + JSON.stringify(res.body)); } else { alert('Oh no! error ' + res.text); } } ); // 使用http var postData = queryString.stringify({name: 'Manny', species: 'cat'}); var options = { path: '/api/pet', method: 'POST', headers: { 'X-API-Key': 'foobar', 'Accept': 'application/json' } }; var req = http.request(options, function (res) { res.on('data', function (chunk) { console.log(chunk); }); }); req.on('error', function (err) { console.log(err); }); req.write(postData); req.end();
從上面的代碼中,咱們能夠看出,使用superagent發送一個post請求,並設置了相關請求頭信息(能夠鏈式操做),相比較使用內置的模塊,要簡單不少。restful
基本用法cookie
在 var request = require('superagent') 以後, request 對象上將會有許多方法可供使用。咱們可使用 get 、 post 等方法名來聲明一個get或者post請求,而後再經過 end() 方法來發出請求。下面是個例子。網絡
request
.get('/search')
.end(function (err, res) {
})app
這裏有一點須要注意,就是隻要當調用了 end() 方法以後,這個請求才會發出。在調用 end() 以前的全部動做其實都是對請求的配置。
咱們在具體使用時,還能夠將請求方法做爲字符串參數,好比
request('GET', '/search').end(function (err, res) {
});
在nodejs客戶端中,還能夠提供絕對路徑,
request
.get('http://www.baidu.com/search')
.end(function (err, res) {
});
其他的http謂語動詞也是可使用,好比 DELETE 、 HEAD 、 POST 、 PUT 等等。使用的時候,咱們只須要變動 request[METHOD] 中的 METHOD 便可。
request
.head('/favicon.ico')
.end(function (err, res) {
});
不過,針對 DELETE 方法,有一點不一樣,由於 delete 是一個保留關鍵字,因此我在使用的時候應該是使用 del() 而不是 delete() 。
request
.del('/user/111')
.end(function (err, res) {
});
superagent默認的http方法是 GET 。就是說,若是你的請求是 get 請求,那麼你能夠省略http方法的相關配置。懶人必備。
request('/search', function(err, res) {
});
設置請求頭
在以前的例子中,咱們看到使用內置的http模塊在設置請求頭信息時,要求傳遞給 http.request 一個 options ,這個 options 包含了全部的請求頭信息。相對這種方式,superagent提供了一種更佳簡單優雅的方式。在superagent中,設置頭信息,使用 set() 方法便可,並且它有多種形式,必能知足你的需求。
// 傳遞key-value鍵值對,能夠一次設置一個頭信息
request
.get('/search')
.set('X-API-Key', 'foobar')
.set('Accept', 'application/json')
.end(function (err, res) {
});
// 傳遞對象,能夠一次設置屢次頭信息
request
.get('/search2')
.set({
'API-Key': 'foobar',
'Accept': 'application/json'
})
.end(function (err, res) {
});
GET請求
在使用 super.get 處理GET請求時,咱們可使用 query() 來處理請求字符串。好比,
request
.get('/search')
.query({name: 'Manny'})
.query({range: '1..5'})
.query({order: 'desc'})
.end(function (err, res) {
});
上面的代碼將會發出一個 /search?name=Manny&range=1..5&order=desc 的請求。
咱們可使用 query() 傳遞一個大對象,將全部的查詢參數都寫入。
request
.get('/search')
.query({
name: 'Manny',
range: '1..5',
order: 'desc'
})
.end(function (err, res) {
});
咱們還能夠簡單粗暴的直接將整個查詢字符串拼接起來做爲 query() 的參數,
request
.get('/search')
.query('name=Manny&range=1..5&order=desc')
.end(function (err, res) {
});
或者是實時拼接字符串,
var name = 'Manny';
var range = '1..5';
var order = 'desc';
request
.get('/search')
.query('name=' + name)
.query('range=' + range)
.query('order=' + order)
.end(function (err, res) {
});
HEAD請求
在 request.head 請求中,咱們也可使用 query() 來設置參數,
request
.head('/users')
.query({
email: 'joe@gmail.com'
})
.end(function (err, res) {
});
上面的代碼將會發出一個 /users?email=joe@gamil.com 的請求。
POST/PUT請求
一個典型的json post請求看起來像下面這樣,
request
.post('/user')
.set('Content-Type', 'application/json')
.send('{"name": "tj", "pet": "tobi"}')
.end(callback);
咱們經過 set() 設置一個合適的 Content-Type ,而後經過 send() 寫入一些post data,最後經過 end() 發出這個post請求。注意這裏咱們 send() 的參數是一個json字符串。
由於json格式如今是一個通用的標準,因此默認的 Content-Type 就是json格式。下面的代碼跟前一個示例是等價的,
request
.post('/user')
.send({name: "tj", pet: "tobi"})
.end(callback);
咱們也可使用多個 send() 拼接post data,
request
.post('/user')
.send({name: "tj"})
.send({pet: 'tobi'})
.end(callback);
send() 方法發送字符串時,將默認設置 Content-Type 爲 application/x-www-form-urlencoded ,屢次 send() 的調用,將會使用 & 將全部的數據拼接起來。好比下面這個例子,咱們發送的數據將爲 name=tj&per=tobi 。
request
.post('/user')
.send('name=tj')
.send('pet=tobi')
.end(callback);
superagent的請求數據格式化是能夠擴展的,不過默認支持 form 和 json 兩種格式,想發送數據以 application/x-www-form-urlencoded 類型的話,則能夠簡單的調用 type() 方法傳遞 form 參數就行, type() 方法的默認參數是 json 。
下面的代碼將會使用 "name=tj&pet=tobi" 來發出一個post請求。
request
.post('/user')
.type('form')
.send({name: 'tj'})
.send({pet: 'tobi'})
end(callback);
設置Content-Type
設置 Content-Type 最經常使用的方法就是使用 set() ,
request
.post('/user')
.set('Content-Type', 'application/json')
.end(callback);
另外一個簡便的方法是調用 type() 方法,傳遞一個規範的 MIME 名稱,包括 type/subtype ,或者是一個簡單的後綴就像 xml , json , png 這樣。好比,
request.post('/user').type('application/json')
request.post('/user').type('json')
request.post('/user').type('png')
設置Accept
跟 type() 相似,設置accept也能夠簡單的調用 accept() 。參數接受一個規範的 MIME 名稱,包括 type/subtype ,或者是一個簡單的後綴就像 xml , json , png 這樣。這個參數值將會被 request.types 所引用。
request.get('/user').accept('application/json')
request.get('/user').accept('json')
request.get('/user').accept('png')
查詢字符串
當用 send(obj) 方法來發送一個post請求,而且但願傳遞一些查詢字符串時,能夠調用 query() 方法,好比向 ?format=json&dest=/login 發送post請求,
request
.post('/')
.query({format: 'json'})
.query({dest: '/login'})
.send({post: 'data', here: 'wahoo'})
.end(callback);
解析響應體
superagent會解析一些經常使用的格式給請求者,當前支持 application/x-www-form-urlencoded , application/json , multipart/form-data 。
JSON/Urlencoded
此種狀況下, res.body 是一個解析過的對象。好比一個請求的響應是一個json字符串 '{"user": {"name": "tobi"}}' ,那麼 res.body.user.name 將會返回 tobi 。
一樣的, x-www-form-urlencoded 格式的 user[name]=tobi 解析完的值是同樣的。 Multipart
nodejs客戶端經過 Formidable 模塊來支持 multipart/form-data 類型,當解析一個 multipart 響應時, res.files 屬性就能夠用了。假設一個請求響應下面的數據,
--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 對象,包括一個磁盤文件路徑,文件名稱,還有其它的文件屬性等。
響應體屬性
response 對象設置了許多有用的標識和屬性。包括 response.text ,解析後的 respnse.body ,頭信息,返回狀態標識等。
Response Text
res.text 包含未解析前的響應內容。基於節省內存和性能因素的緣由,通常只在mime類型可以匹配 text/ , json , x-www-form-urlencoding 的狀況下默認爲nodejs客戶端提供。由於當響應以文件或者圖片等大致積文件的狀況下將會影響性能。
Response Body
跟請求數據自動序列化同樣,響應數據也會自動的解析。當 Content-Type 定義一個解析器後,就能自動解析,默認解析的Content-Type包含 application/json 和 application/x-www-form-urlencoded ,能夠經過訪問 res.body 來訪問解析對象。
Response header fields res.header 包含解析以後的響應頭數據,鍵值都是小寫字母形式,好比 res.header['content-length'] 。 Response Content-Type
Content-Type 響應頭字段是一個特列,服務器提供 res.type 來訪問它,同時 res.charset 默認是空的。好比,Content-Type值爲 text/html; charset=utf8 ,則 res.type 爲 text/html , res.charset 爲 utf8 。
Response Status
響應狀態標識能夠用來判斷請求是否成功以及一些其餘的額外信息。除此以外,還能夠用superagent來構建理想的restful服務器。目前提供的標識定義以下,
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;
中斷請求
要想中斷請求,能夠簡單的調用 request.abort() 便可。
請求超時
能夠經過 request.timeout() 來定義超時時間。當超時錯誤發生時,爲了區別於別的錯誤, err.timeout 屬性被定義爲超時時間(一個 ms 的值)。注意,當超時錯誤發生後,後續的請求都會被重定向。意思就說超時是針對全部的請求而不是單個某個請求。
基本受權
nodejs客戶端目前提供兩種基本受權的方式。
一種是經過相似下面這樣的url,
request.get('http://tobi:learnboost@local').end(callback);
意思就是說要求在url中指明 user:password 。
第二種方式就是經過 auth() 方法。
request
.get('http://local')
.auth('tobi', 'learnboost')
.end(callback);
跟隨重定向
默認是向上跟隨5個重定向,不過能夠經過調用 res.redirects(n) 來設置個數,
request
.get('/some.png')
.redirects(2)
.end(callback);
管道數據
nodejs客戶端容許使用一個請求流來輸送數據。好比請求一個文件做爲輸出流,
var request = require('superagent');
var fs = require('fs');
var stream = fs.createReadStream('path/to/my.json');
var req = request.post('/somewhere');
req.type('json');
stream.pipe(req);
或者將一個響應流寫到文件中,
var request = require('superagent')
var fs = require('fs');
var stream = fs.createWriteStream('path/to/my.json');
var req = request.get('/some.json');
req.pipe(stream);
複合請求
superagent用來構建複合請求很是不錯,提供了低級和高級的api方法。
低級的api是使用多個部分來表現一個文件或者字段, 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) 這兩種形式來調用。添加多個附件也比較簡單,只須要給附件提供自定義的文件名稱,一樣的基礎名稱也要提供。 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的字段很像,你能夠調用 field(name, value) 方法來設置字段。假設你想上傳一個圖片的時候帶上本身的名稱和郵箱,那麼你能夠像下面寫的那樣,
request
.post('/upload')
.field('user[name]', 'Tobi')
.field('user[email]', 'tobi@learnboost.com')
.attach('image', 'path/to/tobi.png')
.end(callback);
壓縮
nodejs客戶端自己對響應體就作了壓縮,並且作的很好。因此這塊你不須要作額外的事情了。
緩衝響應
當想要強制緩衝 res.text 這樣的響應內容時,能夠調用 buffer() 方法。想取消默認的文本緩衝響應,好比 text/plain , text/html 這樣的,能夠調用 buffer(false) 方法。
一旦設置了緩衝標識 res.buffered ,那麼就能夠在一個回調函數裏處理緩衝和沒緩衝的響應。
跨域資源共享
withCredentials() 方法能夠激活發送原始cookie的能力。不過只有在 Access-Control-Allow-Origin 不是一個通配符( ),而且 *Access-Control-Allow-Credentials 爲 true 的狀況下才能夠。
request
.get('http://localhost:4001/')
.withCredentials()
.end(function(err, res, next){
assert(200 == res.status);
assert('tobi' == res.text);
next();
});
異常處理
當請求出錯時,superagent首先會檢查回調函數的參數數量,當 err 參數提供的話,參數就是兩個,以下
request
.post('/upload')
.attach('image', 'path/to/tobi.png')
.end(function(err, res){
});
若是沒有回調函數,或者回調函數只有一個參數的話,能夠添加error事件的處理。
request
.post('/upload')
.attach('image', 'path/to/tobi.png')
.on('error', errorHandle)
.end(function(res){
});
注意:superagent 不認爲 返回 4xx 和 5xx 的狀況是錯誤。好比當請求返回500或者403之類的狀態碼時,能夠經過 res.error 或者 res.status 等屬性來查看。此時並不會有錯誤對象傳遞到回調函數中。當發生網絡錯誤或者解析錯誤時,superagent纔會認爲是發生了請求錯誤,此時會傳遞一個錯誤對象 err 做爲回調函數的第一個參數。
當產生一個4xx或者5xx的http響應, res.error 提供了一個錯誤信息的對象,你能夠經過檢查這個來作某些事情。
if (err && err.status === 404) {
alert('oh no ' + res.body.message);
} else if (err) {
// all other error types we handle generically
}
轉載自http://www.codesec.net/view/183926.html