Node.js 請求模塊
如今,我們的 Web 應用程序傾向於與其他服務進行大量集成,無論是與 Twitter 等 REST 服務交互,還是從 Flickr 下載圖像。使用 Node/JavaScript 是處理此類應用程序的最流行的語言之一。無論哪種方式,你都會發出大量的 HTTP 請求,這意味著你需要一個可靠的模塊來讓編寫代碼變得更容易接受。
request 模塊是迄今為止最流行的(非標準)用於發出 HTTP 請求的 Node 包。實際上,它實際上只是 Node 內置 http 模塊的一個包裝器,因此您可以使用 http
自己實現所有相同的功能 , 但 request
只是讓它變得更容易。
發出 HTTP 請求
雖然 request
中有很多選項可供您使用 (我們將在本文中介紹其中的許多內容),使用起來也非常簡單。這個庫的“hello world”示例就像傳遞 URL 和回調一樣簡單:
const request = require('request');
request('http://stackabuse.com', function(err, res, body) {
console.log(body);
});
上面的代碼向 stackabuse.com 提交一個 HTTP GET 請求,然後將返回的 HTML 打印到屏幕上。這種類型的請求適用於任何 HTTP 端點,無論它返回 HTML、JSON、圖像還是其他任何東西。
request
的第一個參數 可以是 URL 字符串,也可以是選項對象。以下是您在應用程序中會遇到的一些更常見的選項:
url
:HTTP 請求的目標 URLmethod
:要使用的 HTTP 方法(GET、POST、DELETE 等)headers
:要在請求中設置的 HTTP 標頭(鍵值)對象form
:包含鍵值表單數據的對象
const request = require('request');
const options = {
url: 'https://www.reddit.com/r/funny.json',
method: 'GET',
headers: {
'Accept': 'application/json',
'Accept-Charset': 'utf-8',
'User-Agent': 'my-reddit-client'
}
};
request(options, function(err, res, body) {
let json = JSON.parse(body);
console.log(json);
});
使用 options
對象,此請求使用 GET 方法直接從 Reddit 檢索 JSON 數據,該數據在 body
中以字符串形式返回 場地。從這裡,您可以使用 JSON.parse
並將數據用作普通的 JavaScript 對象。
這種相同的請求格式可用於任何類型的 HTTP 方法,無論是 DELETE、PUT、POST 還是 OPTIONS。雖然,並非所有方法都使用完全相同。有些,如 POST 方法,可以在請求中包含數據。有幾種方式可以發送這些數據,其中一些是:
body
:一個Buffer
,String
, 或Stream
對象(如果json
可以是對象 選項設置為true
)form
:鍵值對數據的對象(我們稍後會介紹)multipart
:可以包含自己的標題和正文屬性的對像數組
每個都滿足不同的需求(還有更多發送數據的方法,可以在請求的自述文件的這一部分中找到)。 request
模塊確實包含一些方便的方法,使它們更容易使用,但是,請務必閱讀完整的文檔以避免使您的代碼變得更加困難。
說到輔助方法,調用不同 HTTP 方法的更簡潔的方法是使用提供的相應輔助方法。以下是一些比較常用的:
request.get(options, callback)
request.post(options, callback)
request.head(options, callback)
request.delete(options, callback)
雖然這不會為您節省大量代碼行,但它至少會讓您的代碼更容易理解,因為它允許您只查看被調用的方法,而不必解析所有各種選項來查找它。
表單
無論您是與 REST API 交互,還是創建機器人以在網站上抓取和提交數據,有時您都需要為表單提交數據。與 request
一樣 ,這可以通過幾種不同的方式完成,具體取決於您的需要。
對於常規表單(URL 編碼,MIME 類型為 application/x-www-form-urlencoded
),你最好使用 .post()
使用表單對象的便捷方法:
let options = {
url: 'http://http://mockbin.com/request',
form: {
email: '[email protected]',
password: 'myPassword'
}
};
request.post(options, callback);
這將像 HTML 表單一樣上傳數據,唯一的限制是您不能以這種方式上傳文件。為此,您需要使用 formData
而是選項,它使用下面的表單數據庫。
使用 formData
相反,我們現在可以通過 Buffer
將文件數據傳遞給服務器 s, Stream
s,甚至是非文件數據(和以前一樣)具有簡單的鍵值對。
let formData = {
// Pass single file with a key
profile_pic: fs.createReadStream(__dirname + '/me.jpg'),
// Pass multiple files in an array
attachments: [
fs.readFileSync(__dirname + '/cover-letter.docx'), // Buffer
fs.createReadStream(__dirname + '/resume.docx'), // Stream
],
// Pass extra meta-data with your files
detailed_file: {
value: fs.createReadStream(__dirname + '/my-special-file.txt'),
options: {
filename: 'data.json',
contentType: 'application/json'
}
},
// Simple key-value pairs
username: 'ScottWRobinson'
};
request.post('http://http://mockbin.com/request', {formData: formData}, callback);
這將使用 multipart/form-data
的 MIME 類型發送您的文件 ,即多部分錶單上傳。
雖然這對於大多數用戶的用例來說已經綽綽有餘,但有時您需要更細粒度的控制,例如前/後 CLRF(新行)、分塊或指定您自己的多部分。有關這些額外選項的更多信息,請查看 request
的這一部分 自述文件。
流
在我看來,在許多編程語言中使用最少的特性之一是流。它們的用途不僅限於網絡請求,但這是一個完美的例子,說明了為什麼應該使用它們。有關如何以及為何使用它們的簡短說明,請查看 Node HTTP Servers for Static File Serving 一文的“Streams”部分。
簡而言之,對大量數據(如文件)使用流可以幫助減少應用程序的內存佔用和響應時間。為了使這個更容易使用,每個 request
方法可以pipe
他們的輸出到另一個流。
免費電子書:Git Essentials
查看我們的 Git 學習實踐指南,其中包含最佳實踐、行業認可的標準以及隨附的備忘單。停止谷歌搜索 Git 命令並真正學習 它!
在此示例中,我們使用 GET 請求下載 Node.js 徽標並將其流式傳輸到本地文件:
let fileStream = fs.createWriteStream('node.png');
request('https://nodejs.org/static/images/logos/nodejs-new-white-pantone.png').pipe(fileStream);
一旦 HTTP 請求開始返回下載圖像的部分內容,它就會將該數據“管道”直接發送到文件“node.png”。
以這種方式下載文件還有其他一些好處。流非常適合在下載數據時對數據應用轉換。因此,例如,假設您正在使用 request
下載大量敏感數據 需要立即加密。為此,您可以通過管道輸出 request
來應用加密轉換 到crypto.createCipher:
let url = 'http://example.com/super-sensitive-data.json';
let pwd = new Buffer('myPassword');
let aesTransform = crypto.createCipher('aes-256-cbc', pwd);
let fileStream = fs.createWriteStream('encrypted.json');
request(url)
.pipe(aesTransform) // Encrypts with aes256
.pipe(fileStream) // Write encrypted data to a file
.on('finish', function() {
console.log('Done downloading, encrypting, and saving!');
});
很容易忽略流,很多人在編寫代碼時都會這樣做,但是它們可以極大地幫助您提高性能,尤其是對於像 request
這樣的庫 .
雜項。配置
HTTP 請求不僅僅是指定 URL 和下載數據。對於較大的應用程序,尤其是那些必須支持更廣泛環境的應用程序,您的請求可能需要處理相當多的配置參數,例如代理或特殊的 SSL 信任證書。
一項重要的雜項。要指出的功能是 request.defaults()
方法,它允許你指定默認參數,這樣你就不必為你提出的每個請求都提供它們。
let req = request.defaults({
headers: {
'x-access-token': '123abc',
'User-Agent': 'my-reddit-client'
}
});
req('http://your-api.com', function(err, res, body) {
console.log(body);
});
現在,在上面的示例中,所有使用 req
發出的請求 將始終具有標題 x-access-token
和 User-Agent
放。這非常適合設置此類標頭、代理服務器或 TLS/SSL 配置。
在本節的其餘部分,我們將介紹一些您會遇到的更常見的功能:
代理
無論您的計算機是在公司代理後面,還是您想將您的流量重定向到另一個國家,在某些時候您可能需要指定一個代理地址。實現這一點的最簡單方法是使用 proxy
選項,它需要一個代理流量的地址:
let options = {
url: 'https://www.google.com',
proxy: 'http://myproxy.com'
};
request(options, callback);
options
object 是指定代理的一種方法,但 request
還使用以下環境變量來配置代理連接:
- HTTP_PROXY / http_proxy
- HTTPS_PROXY / https_proxy
- NO_PROXY / no_proxy
這為您提供了更多控制權,例如設置哪些網站不應該 通過 NO_PROXY
代理 變量。
TLS/SSL
有時 API 需要有一些額外的安全性,因此需要客戶端證書。這實際上在私有企業 API 中相當普遍,因此值得了解如何執行此操作。
另一種可能的情況是您希望您的 HTTP 請求明確信任某些證書頒發機構,其中可能包括您或您的公司自簽名的證書。
與到目前為止我們看到的所有其他配置一樣,這些都是在 options
中設置的 對象:
const fs = require('fs');
const request = require('request');
let myCertFile = fs.readFileSync(__dirname + '/ssl/client.crt')
let myKeyFile = fs.readFileSync(__dirname + '/ssl/client.key')
let myCaFile = fs.readFileSync(__dirname + '/ssl/ca.cert.pem')
var options = {
url: 'https://mockbin.com/request',
cert: myCertFile,
key: myKeyFile,
passphrase: 'myPassword',
ca: myCaFile
};
request.get(options);
基本認證
使用基本訪問身份驗證的站點仍然可以使用 auth
訪問 選項:
const request = require('request');
var options = {
url: 'https://mockbin.com/request',
auth: {
username: 'ScottWRobinson',
password: 'myPassword'
}
};
request.get(options);
此選項將 HTTP 標頭之一設置為 "authorization": "Basic c2NvdHQ6cGFzc3dvcmQh"
. “授權”標頭中的“基本”字符串聲明這是一個基本身份驗證請求,後面的字母數字字符串是我們的用戶名和密碼的 RFC2045-MIME 編碼(Base64 的一種變體)。
重定向
我發現在某些應用程序中,例如網頁抓取,在很多情況下您需要遵循重定向才能使您的請求成功。您可能已經猜到了,默認情況下有一個選項可以指定是否遵循重定向,但是 request
更進一步,將讓您提供一個函數,可用於有條件地確定是否應遵循重定向。
一些重定向選項是:
followRedirect
:如果true
,然後遵循所有 HTTP 3xx 重定向。或提交function(res) {}
用於確定是否遵循重定向followAllRedirects
:遵循所有非 GET HTTP 3xx 重定向maxRedirects
:跟踪鏈接重定向的最大次數(默認為 10)
結論
毫無疑問request
是一個功能強大的模塊,可能是您經常使用的模塊。鑑於它提供的所有功能,它可以作為一個很好的起點,從網絡爬蟲到 API 的客戶端庫。
request
可以使用更多的選項和配置 比我們在這裡展示的更多,所以請務必查看文檔以獲取更多詳細信息。請記住,並非模塊中的所有內容都記錄在案,因此您可能需要進行更多搜索/實驗才能找到答案。
你用過request
在你的任何項目中?如果有,怎麼做?