[轉] SuperAgent使用文檔


本篇文檔是參考SuperAgent英文文檔翻譯整理成的。前段時間,在一個爬蟲項目中用到了SuperAgent,因為遇到了一些坑,就詳細地查閱了一番官方文檔,后為便於朋友查閱參考,我將翻譯的文檔進行了簡要整理。后期,我還會針對SuperAgent使用中遇到的一些問題進行完善,並附於文末Issue章節。同時也歡迎大家分享自己在使用SuperAgent過程中遇到的一些問題和解決方法。

1 簡介

SuperAgent是一個輕量級、靈活的、易讀的、低學習曲線的客戶端請求代理模塊,使用在NodeJS環境中。

官方文檔:http://visionmedia.github.io/superagent

使用示例:

var request = require('superagent') request .post('/api/pet') .send({ name: 'Manny', species: 'cat' }) .set('X-API-Key', 'foobar') .set('Accept', 'application/json') .then(res => { alert('yay got ' + JSON.stringify(res.body)); }); 

在后面的講解中我們都使用request表示superagent對象,代碼中也省略如下部分:

var request = require('superagent') 

2 請求

通過調用request對象then()end()方法,或使用await關鍵字,發送一個請求。

request
  .get('/search') .then(res => { // res.body, res.headers, res.status }) .catch(err => { // err.message, err.response }); 

請求的方法類型(DELETEHEADPATCHPOSTPUT)可以通過如下字符串來指定:

// 指定使用GET方法 request('GET', '/search') .then(function (response) { // success }, function (error) { // failure }); 

也可以使用end()方法

request('GET', '/search') .end(function(error, response){ if (response.ok) { } }); 

可以使用完整的URLs,由於同源策略的原因,這需要服務器實現了跨域訪問。

request
  .get('https://example.com/search') .then(res => { }); 

除了上述使用的GET方法外,也可以使用DELETEHEADPATCHPOSTPUT方法,只需要簡單地更改一下方法的名稱。

request
  .head('/favicon.ico') .then(response => { }); 

在舊版本IE瀏覽器中delete是系統的關鍵字,為了兼容這一點,可以調用del()方法來避免沖突。

request
  .del('/book/1') .end(function(response){ }); 

request默認使用GET方法發送請求,可以簡寫成如下:

request('/search', (error, response) => { }); 

3 HTTP/2

如果要使用HTTP/2協議發送請求,可以調用http2()方法。目前還暫不支持對服務器 HTTP/2能力的檢測。

const request = require('superagent'); const res = await request .get('https://example.com/h2') .http2(); 

4 設置頭部字段

報文header字段設置通過調用set()方法。

request
  .get('/search') .set('API-Key', 'foobar') .set('Accept', 'application/json') .then(callback); 

你也可以傳遞一個對象來設置多個字段:

request
  .get('/search') .set({ 'API-Key': 'foobar', ' Accept': 'application/json' }) .then(callback); 

5 GET請求

當我們使用GET請求傳遞查詢字符串的時候,可以使用query()方法,同時傳遞一個對象作為參數,下面的代碼將產生一個URL為/search?query=Manny&range=1..5&order=desc請求:

request
  .get('/search') .query({ query: 'Manny' }) .query({ range: '1..5' }) .query({ order: 'desc' }) .then(response => { }); 

或者傳遞一個對象

request
  .get('/search') .query({ query: 'Manny', range: '1..5', order: 'desc' }) .then(response => { }); 

query()也接受一個字符串作為參數

request
  .get('/querystring') .query('search=Manny&range=1..5') .then(response => { }) 

參數拼接字符&也可以用下面的方式替代:

request
  .get('/querystring') .query('search=Manny') .query('range=1..5') .then(response => { }); 

6 HEAD請求

query()方法也可以用於HEAD請求,下面的代碼將會產生一個URL為 /users?email=joe@smith.com的請求:

request
  .head('/users') .query({ email: 'joe@smith.com' }) .then(response => { }); 

7 POST / PUT請求

一個典型的JSON POST請求的代碼實現如下,設置相應的Content-type頭字段,再寫入數據。在這個例子里,僅使用JSON字符串:

request.post('/user') .set('Content-Type', 'application/json') .send('{"name":"tj","pet":"tobi"}') .then(callback) 

JSON成為通用的數據格式后,request對象默認Content-type類型就是application/json,因此代碼就可以簡化為:

request.post('/user') .send('{"name":"tj","pet":"tobi"}') .then(callback) 

也可以多次調用send()方法完成

request.post('/user')
  .send({ name: 'tj' })
  .send({ pet: 'tobi' })
  .then(callback

默認情況下,發送字符串時Content-type會被設置為application/x-www-form-urlencoded,多次調用send()方法會使用&連接起來,下面的代碼中最終結果為:name=tj&pet=tobi

request.post('/user')
  .send('name=tj')
  .send('pet=tobi')
  .then(callback);

SuperAgent請求的數據格式是可以擴展的,不過默認支持“form”和“json”兩種格式,想要以application/x-www-form-urlencoded格式發送數據的話,則可以調用type()方法並傳入'form'參數,這里默認的參數是“json”。下面的請求中,POST請求體為name=tj&pet=tobi

request.post('/user')
  .type('form')
  .send({ name: 'tj' })
  .send({ pet: 'tobi' })
  .then(callback)

支持發送FormData對象。下面的例子中發送id="myForm"<form>表單數據:

request.post('/user') .send(new FormData(document.getElementById('myForm'))) .then(callback) 

提示:FormData類型其實是在XMLHttpRequest 2級定義的,它是為序列化表以及創建與表單格式相同的數據(當然是用於XHR傳輸)提供便利。

8 Content-Type設置

通常使用set()方法

request.post('/user')
  .set('Content-Type', 'application/json')

簡便的方法是調用.type()方法,傳遞一個規范的MIME名稱,包括type/subtype,或者一個簡單的后綴就像xmljsonpng這樣。例如:

request.post('/user')
  .type('application/json')

request.post('/user')
  .type('json')

request.post('/user')
  .type('png')

9 序列化請求體

SuperAgent會自動序列化JSON和表單數據,你也可以為其他類型設置自動序列化:

request.serialize['application/xml'] = function (obj) { return 'string generated from obj'; }; // going forward, all requests with a Content-type of // 'application/xml' will be automatically serialized 

如果你希望以自定義格式發送數據,可以通過.serialize()方法為每個請求設置相應的序列化方法,以替換內置序列化方法:

request
    .post('/user') .send({foo: 'bar'}) .serialize(obj => { return 'string generated from obj'; }); 

10 重發請求

當給定retry()方法時,SuperAgent將自動重試請求,如果它們以短暫的方式失敗或者可能由於因特網連接不正常而失敗。

這個方法有兩個可選參數:重試次數(默認值3)和回調函數。它在每次重發之前調用回調(error, res)。回調可以返回true/false,以決定是否要重發請求。

request
  .get('https://example.com/search') .retry(2) // or: .retry(2, callback) .then(finished); 

需要注意的是:應該只對HTTP等冪請求使用retry()方法(即,到達服務器的多個請求不會導致不希望的副作用,如重復購買,否則會產生多個訂單)。

11 設置Accept

type()方法一樣,這里可以調用accept()方法來設置Accept接受類型,這個值將會被request.types所引用,支持傳遞一個規范的MIME名稱,包括type/subtype,或者一個簡單的后綴:xmljson,``png等。例如:

request.get('/user') .accept('application/json') request.get('/user') .accept('json') request.post('/user') .accept('png') 

Facebook和接收JSON:如果你是在調用Facebook的API,確保請求頭中Accept: application/json 。否則,Facebook 將返回Content-Type: text/javascript; charset=UTF-8響應, SuperAgent將不會解析這個響應,讀取響應體會得到undefined。你需要在請求對象request加上request.accept('json')或者request.header('Accept', 'application/json')代碼。

12 查詢字符串

調用.query()方法可以自動生成查詢字符串,比如向URL為?format=json&dest=/login發送一個post請求:

request
  .post('/')
  .query({ format: 'json' })
  .query({ dest: '/login' })
  .send({ post: 'data', here: 'wahoo' })
  .then(callback);

默認情況下,查詢字符串的拼裝是沒有特定的順序。調用sortQuery()方法將默認按照ASCII碼順序進行,你也可以傳遞一個比較函數來指定排序規則,比較函數需要傳遞兩個參數(在回調過程中會自動傳遞進兩個參數,這兩個參數就是用於比較的查詢字符串),返回值是正整數、負整數或者0。

// 選擇默認排序 request.get('/user') .query('name=Nick') .query('search=Manny') .sortQuery() .then(callback) // 客制化的排序函數 request.get('/user') .query('name=Nick') .query('search=Manny') .sortQuery((a, b) => a.length - b.length) .then(callback) 

上述客制化的排序函數中,ab實際上就是sortQuery()回調過程中傳遞進去的兩個查詢字符串,按照查詢字符串長度來排序的,長度大的排在前面。

13 TLS選項

在Node.js中使用SuperAgent,支持對HTTPS請求的下列配置:

  • ca():將CA證書設置為信任
  • cert():設置客戶端證書鏈
  • key(): 設置客戶端私鑰
  • pfx(): 設置客戶端PFX或PKCS12編碼的私鑰和證書鏈

更多信息可以查看:https.request 官方文檔.

var key = fs.readFileSync('key.pem'), cert = fs.readFileSync('cert.pem'); request .post('/client-auth') .key(key) .cert(cert) .then(callback); 
var ca = fs.readFileSync('ca.cert.pem'); request .post('https://localhost/private-ca-server') .ca(ca) .then(res => {}); 

14 解析響應體

SuperAgent 可以解析常用的響應體,目前支持application/x-www-form-urlencodedapplication/json, 和multipart/form-data格式。如下代碼,你也可以對其它類型的響應體設置相應的解析方法:

// 瀏覽器端使用SuperAgent request.parse['application/xml'] = function (str) { return {'object': 'parsed from str'}; }; // Node中使用SuperAgent request.parse['application/xml'] = function (res, cb) { // 解析響應內容,設置響應體代碼 cb(null, res); }; // 自動解析響應體 

通過調用buffer(true)parse(fn)的配合,你可以設置一個定制的解析器(定制的解析器優先於內置解析器)。 如果沒有啟用響應緩沖(buffer(false)),那么響應事件的觸發將不會等待主體解析器完成,因此響應體將不可用。

14.1 JSON/Urlencoded

response.body是解析后的內容對象,比如對於一個請求響應'{"user":{"name":"tobi"}}'字符串,response.body.user.name會返回"tobi"。同樣的,與x-www-form-urlencoded格式的"user[name]=tobi"解析后值也是一樣,只支持嵌套的一個層次,如果需要更復雜的數據,請使用JSON格式。

數組會以重復鍵名的方式進行發送,send({color: ['red','blue']})會發送"color=red&color=blue"。如果你希望數組鍵的名稱包含"[]",則需要自己添加,SuperAgent是不會自動添加。

14.2 Multipart

Node客戶端通過Formidable模塊來支持multipart/form-data類型,當解析一個multipart響應時,response.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對象,包括一個磁盤文件路徑、文件名稱,還有其它的文件屬性。

14.3 Binary

在瀏覽器中可以使用responseType('blob')來請求處理二進制格式的響應體。在Node.js中運行此API是不必要的。此方法的支持參數值為:

  • 'blob':會被傳遞為XmlHTTPRequestresponseType屬性。
  • 'arraybuffer':會被傳遞為XmlHTTPRequestresponseType屬性。
req.get('/binary.data') .responseType('blob') .then(res => { // res.body will be a browser native Blob type here }); 

更多的信息可以查看:xhr.responseType 文檔.

15 響應對象屬性

SuperAgent請求得到響應后,響應對象的屬性主要有:

  • text:未解析前的響應內容,字符串類型。一般只在mime類型能夠匹配"text/""json""x-www-form-urlencoding"的情況下,這個屬性才會有效,默認為nodejs客戶端提供;

  • body:響應數據解析后的對象,對象類型。

  • header:解析之后的響應頭數據,數組類型。

  • type:響應報文的Content-Type值,字符串類型。

  • charset:響應的字符集,字符串類型。

  • status:響應狀態標識。

  • statusCode:響應的狀態碼,數整數類型。如:200、302、404、500等。

15.1 text

response.text包含未解析前的響應內容,一般只在mime類型能夠匹配"text/""json""x-www-form-urlencoding"的情況下,這個屬性才會有效,默認為nodejs客戶端提供,這是出於節省內存的考慮。因為緩沖大數據量的文本(如multipart文件或圖像)的效率非常低。要強制緩沖,請參閱“響應緩沖”部分。

15.2 body

SuperAgent請求數據自動序列化一樣,響應數據也會自動的解析,當為一個Content-Type定義一個解析器后,就能自動解析,默認解析包含application/jsonapplication/x-www-form-urlencoded,可以通過response.body來訪問解析對象.

15.3 header fields

response.header包含解析之后的響應頭數據,字段值都是Node處理成小寫字母形式,如response.header['content-length']

15.4 Content-Type

Content-Type響應頭字段是一個特列,服務器提供response.type來訪問它,默認response.charset是空的(如果有的話,則為指定類型),例如Content-Type值為"text/html; charset=utf8",則response.typetext/html,response.charset"utf8"

15.5 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; 

16.中止請求

可以通過req.abort()來中止請求。

17.請求超時

有時網絡和服務器會“卡住”,並且在接受請求后從不響應。設置超時以避免請求永遠等待。

  • req.timeout({deadline:ms})req.timeout(ms): ms是大於0的毫秒數。為整個請求設置一個截止時間(包括所有上傳、重定向、服務器處理時間)完成。如果在那個時間內沒有得到完整的響應,請求將被中止。

  • req.timeout({response:ms}):設置等待第一個字節從服務器到達的最大時間,但不限制整個下載可以消耗多長時間。響應超時應該比服務器響應的時間長至少幾秒鍾,因為它還包括進行DNS查找、TCP/IP和TLS連接的時間,以及上傳請求數據的時間。

你應該同時使用deadlineresponse超時。通過這種方式,你可以通過較短的response超時來快速檢測無響應網絡,並且使用較長的deadline來在緩慢但可靠的網絡上提供一個合適的時間。注意,這兩個計時器都限制了上傳文件的上傳時間。如果上傳文件,則使用長時間超時。

request
  .get('/big-file?network=slow') .timeout({ response: 5000, // Wait 5 seconds for the server to start sending, deadline: 60000, // but allow 1 minute for the file to finish loading. }) .then(res => { /* responded in time */ }, err => { if (err.timeout) { /* timed out! */ } else { /* other error */ } }); 

超時錯誤會提供一個timeout屬性。

18.認證

Node和瀏覽器中都可以通過auth()方法來完成認證。

request
  .get('http://local') .auth('tobi', 'learnboost') .then(callback); 

nodejs客戶端也可以通過傳遞一個像下面這樣的URL:

request.get('http://tobi:learnboost@local').then(callback); 

默認在瀏覽器中只使用基本的認證方式,你也可以添加{type:'auto'},以啟用瀏覽器中內置的所有方法(摘要、NTLM等):

request.auth('digest', 'secret', {type:'auto'})

19.跟隨重定向

默認是向上跟隨5個重定向,可以通過調用.res.redirects(n)來設置個數:

request
  .get('/some.png') .redirects(2) .then(callback); 

20.全局狀態代理

20.1 保存cookies

在Node SuperAgent中,默認情況下不保存cookie,但是可以使用.agent()方法創建一個含有cookie的SuperAgent副本。每個副本都有一個單獨的cookie數據。

const agent = request.agent(); agent .post('/login') .then(() => { return agent.get('/cookied-page'); }); 

在瀏覽器中,cookie由瀏覽器自動管理,因此.agent()不會格式化處理cookies。

20.2 多請求的默認選項

使用agent進行的多個請求中,agent調用的常規方法也將默認用於agent的后續所有的請求中。這些常規方法包括:use, on, once, set, query, type, accept, auth, withCredentials, sortQuery, retry, ok, redirects, timeout, buffer, serialize, parse, ca, key, pfx, cert

const agent = request.agent() .use(plugin) .auth(shared); await agent.get('/with-plugin-and-auth'); await agent.get('/also-with-plugin-and-auth'); 

21.管道數據

在nodejs客戶端中,可以使用一個請求流來傳輸數據。需要注意的是:用pipe()取代了end()then()方法。

下面是將文件內容作為請求進行管道傳輸例子:

const request = require('superagent'); const fs = require('fs'); const stream = fs.createReadStream('path/to/my.json'); const req = request.post('/somewhere'); req.type('json'); stream.pipe(req); 

注意,在管道傳輸到請求時,superagent使用分塊傳輸編碼發送管道數據,這不是所有服務器(例如Python WSGI服務器)都支持的。

下面是輸送一個響應流到文件的管道傳輸例子:

const stream = fs.createWriteStream('path/to/my.json'); const req = request.get('/some.json'); req.pipe(stream); 

不能將管道、回調或promise混合在一起使用,不能嘗試對end()response對象進行管道操作(pipe()),如下所示:

// 不能做下面的操作 const stream = getAWritableStream(); const req = request .get('/some.json') // BAD: this pipes garbage to the stream and fails in unexpected ways .end((err, this_does_not_work) => this_does_not_work.pipe(stream)) const req = request .get('/some.json') .end() // BAD: this is also unsupported, .pipe calls .end for you. .pipe(nope_its_too_late); 

22.Multipart/form-data請求

superagen提供了attach()field()方法用於構建multipart/form-data請求。

當你使用了field()或者attach(),你就不能使用 send()方法,你也不能設置 Content-Type (superagen會自動設置糾正后的type)。

22.1 附件

可以使用attach(name, [file], [options])進行文件發送。你可以通過多次調用attach()附加多個文件。attach()的參數說明如下:

  • name:文件名
  • file:文件路徑字符串,或Blob/Buffer對象。
  • options :(可選)字符串或自定義文件名或{filename: string}對象。在Node中也支持{contentType: 'mime/type'}。在瀏覽器中創建一個具有適當類型的Blob
request
  .post('/upload')
  .attach('image1', 'path/to/felix.jpeg')
  .attach('image2', imageBuffer, 'luna.jpeg')
  .field('caption', 'My cats')
  .then(callback);

22.2 字段值

與HTML中表單的字段類似,你可以調用field(name,value)方法來設置字段,假設你想上傳一個圖片的並附帶自己的名稱和郵箱,那么你可以像下面這樣:

 request
   .post('/upload')
   .field('user[name]', 'Tobi')
   .field('user[email]', 'tobi@learnboost.com')
   .field('friends[]', ['loki', 'jane'])
   .attach('image', 'path/to/tobi.png')
   .then(callback);

23.壓縮

NodeJS客戶端本身就提供壓縮響應內容,所以你不需要做任何其它處理。

24.響應緩沖

為了強制緩沖response.text這樣未解析前的響應內容(一般只在mime類型能夠匹配"text/","json","x-www-form-urlencoding"的情況下才進行緩沖),可以調用buffer()方法,想取消默認的文本緩沖響應像text/plain, text/html這樣的,可以調用buffer(false)方法。

// 強制緩沖 request .get('/userinfo') .buffer(true) .then(callback) // 取消緩沖 request .get('/userinfo') .buffer(false) .then(callback) 

當緩沖response.buffered標識有效了,那么就可以在一個回調函數里處理緩沖和未緩沖的響應.

25.跨域資源共享(CORS)

出於安全原因,瀏覽器將阻止跨源請求,除非服務器使用CORS頭進行選擇。瀏覽器還將做出額外的選項請求,以檢查服務器允許的HTTP頭和方法。更多信息可參閱:CORS.

withCredentials()方法可以激活發送原始cookie的能力,不過只有在Access-Control-Allow-Origin不是一個通配符(*),並且Access-Control-Allow-Credentials’true’的情況下才行。

request
  .get('https://api.example.com:4001/') .withCredentials() .then(res => { assert.equal(200, res.status); assert.equal('tobi', res.text); }) 

26.錯誤處理

回調函數總是會傳遞兩個參數:error 錯誤和response 響應。如果沒有發生錯誤,第一個參數將為null

request
 .post('/upload') .attach('image', 'path/to/tobi.png') .then(response => { }); 

你可以加入監聽錯誤的代碼,錯誤產生之后會執行監聽代碼。

request
  .post('/upload') .attach('image', 'path/to/tobi.png') .on('error', handle) .then(response => { }); 

注意:
superagent默認情況下,對響應4xx和5xx的認為不是錯誤,例如當響應返回一個500或者403的時候,這些狀態信息可以通過response.errorresponse.status和其它的響應屬性來查看。

不產生響應的網絡故障、超時和其他錯誤將不包含response.errorresponse.status屬性。

如果希望處理404個或其他HTTP錯誤響應,可以查詢error.status屬性。當發生HTTP錯誤(4xx或5xx響應)時,response.error屬性是error對象,這可以用來作以下檢查:

if (error && error.status === 404) { alert('oh no ' + response.body.message); } else if (error) { // all other error types we handle generically } 

或者,可以使用ok(callback)方法來判斷響應是否是錯誤。對ok()的回調得到響應,如果響應成功,則返回true。

request.get('/404') .ok(res => res.status < 500) .then(response => { // reads 404 page as a successful response }) 

27.進度跟蹤

superagent在大型文件的上傳和下載過程中觸發progress事件。

request.post(url) .attach('field_name', file) .on('progress', event => { /* the event is: { direction: "upload" or "download" percent: 0 to 100 // may be missing if file size is unknown total: // total file size, may be missing loaded: // bytes downloaded or uploaded so far } */ }) .then() 

event屬性包括:

  • directionuploaddownload
  • percent0100 ,文件大小未知的話為無效
  • total:文件總大小,可能為無效
  • loaded: 已經下載或上傳的字節數

28.Promise和Generator支持

SuperAgent的請求是一個“thenable”對象,它與JavaScript承諾和異步/等待語法兼容。

如果你正在使用promises,那么就不要再調用end()pipe()方法。任何使用then()或者await操作都會禁用所有其他使用請求的方式。

像CO或類似KOA這樣的Web框架,可以在superagent使用yield

const req = request .get('http://local') .auth('tobi', 'learnboost'); const res = yield req; 

請注意,superagent期望全局promises對象存在。在Internet Explorer或Node.js 0.10中需要使用polyfill組件。

29.瀏覽器和Node版本

SuperAgent有兩個實現:一個是用於web瀏覽器(使用XHR)的版本,另一個是用於Node.JS (使用核心的http模塊)版本。

30.3XX處理

HTTP 3XX是重定向報文,superagent默認會自動跟蹤下去,我們也不能使用redirect(0)的方法來禁止重定向,因此需要使用原生的http來處理。

request.post({ url: '/login', }, function (err, res, body) { if (!err && (res.statusCode == 301 || res.statusCode == 302)) { // 登錄成功后服務端返回重定位報文 cookie += ';' + res.headers['set-cookie'] res1.redirect('listall') } else if (res.statusCode == 200) { // 登錄失敗服務端會返回200 // ... } else { // 其他錯誤信息處理 console.log(err) } }) 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM