如何在Node.js中使用核心HTTP创建HTTP客户端
作者选择了 COVID-19 Relief Fund 作为 Write for DOnations 计划的一部分来接受捐赠。
介绍
现代 Web 应用程序与其他服务器通信以完成任务是很常见的。 例如,允许您在线购买图书的 Web 应用程序可能涉及客户订单服务器、图书库存服务器和支付服务器之间的通信。 在此设计中,不同的服务通过 Web API(允许您以编程方式发送和接收数据的标准格式)进行通信。 在 Node.js 应用程序中,您可以通过发出 HTTP 请求与 Web API 进行通信。
Node.js 捆绑了一个 http 和一个 https 模块。 这些模块具有 创建 HTTP 服务器 的功能,以便 Node.js 程序可以响应 HTTP 请求。 他们还可以向其他服务器发出 HTTP 请求。 这一关键功能使 Node.js 程序员能够使用 Node.js 创建现代的、API 驱动的 Web 应用程序。 由于它是一个核心模块,因此您无需安装任何库即可使用它。
在本教程中,您将使用 https
模块向 JSON Placeholder 发出 HTTP 请求,这是一个用于测试目的的假 REST API。 您将从发出 GET
请求开始,这是接收数据的标准 HTTP 请求。 然后,您将查看自定义请求的方法,例如添加标头。 最后,您将发出 POST
、PUT
和 DELETE
请求,以便您可以修改外部服务器中的数据。
先决条件
- 本教程要求您安装了 Node.js。 安装后,您将能够访问整个教程中使用的
https
模块。 本教程使用 Node.js 版本 10.19.0。 要在 macOS 或 Ubuntu 18.04 上安装 Node.js,请按照 如何在 macOS 上安装 Node.js 和创建本地开发环境或 使用 PPA 安装 部分中的步骤进行操作。 X199X]如何在 Ubuntu 18.04 上安装 Node.js。 - 用于发送 HTTP 请求的方法具有基于流的 API。 在 Node.js 中,流是事件发射器的实例。 响应来自流的数据的方式与响应来自事件的数据的方式相同。 如果您有兴趣,可以阅读我们的 在 Node.js 中使用事件发射器 指南,获得更深入的事件发射器知识。
第 1 步 — 发出 GET
请求
当您与 API 交互时,您通常会发出 GET
请求以从 Web 服务器检索数据。 在这一步中,您将了解在 Node.js 中发出 GET
请求的两个函数。 您的代码将从可公开访问的 API 中检索用户配置文件的 JSON array。
https
模块有两个函数可以发出GET
请求——get()
函数只能发出GET
请求,request()
函数,它发出其他类型的请求。 您将首先使用 get()
函数发出请求。
使用 get()
发出请求
使用 get()
函数的 HTTP 请求具有以下格式:
https.get(URL_String, Callback_Function) { Action }
第一个参数是一个字符串,其中包含您要向其发出请求的端点。 第二个参数是一个 回调函数 ,用于处理响应。
首先,设置您的编码环境。 在您的终端中,创建一个文件夹来存储本指南的所有 Node.js 模块:
mkdir requests
输入该文件夹:
cd requests
在文本编辑器中创建并打开一个新文件。 本教程将使用 nano
,因为它在终端中可用:
nano getRequestWithGet.js
要在 Node.js 中发出 HTTP 请求,请通过添加以下行来导入 https
模块:
请求/getRequestWithGet.js
const https = require('https');
注意::Node.js 有一个 http
和一个 https
模块。 它们具有相同的功能并以相似的方式运行,但 https
通过 传输层安全性 (TLS/SSL) 发出请求。 由于您使用的 Web 服务器可通过 HTTPS 访问,因此您将使用 https
模块。 如果您正在向仅具有 HTTP 的 URL 发出请求,那么您将使用 http
模块。
现在使用 http
object 向 API 发出 GET
请求以检索用户列表。 您将使用 JSON Placeholder,一个公开可用的 API 进行测试。 此 API 不会记录您在请求中所做的任何更改。 它模拟一个真实的服务器,只要你发送一个有效的请求,它就会返回模拟的响应。
在文本编辑器中编写以下突出显示的代码:
请求/getRequestWithGet.js
const https = require('https'); let request = https.get('https://jsonplaceholder.typicode.com/users?_limit=2', (res) => { });
如函数签名中所述,get()
函数有两个参数。 第一个是您以 string 格式发出请求的 API URL,第二个是处理 HTTP 响应的回调。 要从您的响应中读取数据,您必须在回调中添加一些代码。
HTTP 响应带有状态码。 状态码是一个数字,表示响应的成功程度。 200 到 299 之间的状态代码是肯定响应,而 400 到 599 之间的代码是错误。 您可以在我们的 如何排除常见 HTTP 错误代码 指南中了解有关状态代码的更多信息。
对于此请求,成功的响应将具有 200 状态代码。 您在回调中要做的第一件事是验证状态码是否符合您的预期。 将以下代码添加到回调函数中:
请求/getRequestWithGet.js
const https = require('https'); let request = https.get('https://jsonplaceholder.typicode.com/users?_limit=2', (res) => { if (res.statusCode !== 200) { console.error(`Did not get an OK from the server. Code: ${res.statusCode}`); res.resume(); return; } });
回调中可用的响应对象具有存储状态代码的 statusCode
属性。 如果状态码不是 200,则将错误记录到控制台并退出。
请注意具有 res.resume()
的行。 您包括该行以提高性能。 发出 HTTP 请求时,Node.js 将使用随请求发送的所有数据。 res.resume()
方法告诉 Node.js 忽略流的数据。 反过来,Node.js 通常会比将数据留给 垃圾收集 更快地丢弃数据——这是一个释放应用程序内存的周期性过程。
现在您已捕获错误响应,添加代码以读取数据。 Node.js 响应以块的形式流式传输它们的数据。 检索数据的策略将是侦听数据何时来自响应,整理所有块,然后解析 JSON,以便您的应用程序可以使用它。
修改请求回调以包含以下代码:
请求/getRequestWithGet.js
const https = require('https'); let request = https.get('https://jsonplaceholder.typicode.com/users?_limit=2', (res) => { if (res.statusCode !== 200) { console.error(`Did not get an OK from the server. Code: ${res.statusCode}`); res.resume(); return; } let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('close', () => { console.log('Retrieved all data'); console.log(JSON.parse(data)); }); });
您首先创建一个新变量 data
,它是一个空字符串。 您可以将数据存储为表示字节数据的数字数组或字符串。 本教程使用后者,因为它更容易将 JSON 字符串转换为 JavaScript 对象。
创建 data
变量后,您将创建一个 事件侦听器 。 Node.js 以块的形式流式传输 HTTP 响应的数据。 因此,当响应对象发出 data
事件时,您将获取它接收到的数据并将其添加到您的 data
变量中。
当接收到来自服务器的所有数据时,Node.js 会发出 close
事件。 此时,您解析存储在 data
中的 JSON 字符串并将结果记录到控制台。
您的 Node.js 模块现在可以与 JSON API 通信并记录用户列表,这将是一个包含三个用户的 JSON 数组。 但是,您可以先进行一点小改进。
如果您无法发出请求,此脚本将引发错误。 例如,如果您失去互联网连接,您可能无法提出请求。 添加以下代码以在您无法发送 HTTP 请求时捕获错误:
请求/getRequestWithGet.js
... res.on('data', (chunk) => { data += chunk; }); res.on('close', () => { console.log('Retrieved all data'); console.log(JSON.parse(data)); }); }); request.on('error', (err) => { console.error(`Encountered an error trying to make a request: ${err.message}`); });
当发出请求但无法发送时,请求对象会发出 error
事件。 如果发出 error
事件但未侦听,Node.js 程序将崩溃。 因此,要捕获错误,您可以使用 on()
函数添加事件侦听器并侦听 error
事件。 当您收到错误时,您会记录其消息。
这就是这个文件的所有代码。 按 CTRL+X
保存并退出 nano
。
现在用 node
执行这个程序:
node getRequestWithGet.js
您的控制台将显示此响应:
OutputRetrieved all data [ { id: 1, name: 'Leanne Graham', username: 'Bret', email: 'Sincere@april.biz', address: { street: 'Kulas Light', suite: 'Apt. 556', city: 'Gwenborough', zipcode: '92998-3874', geo: [Object] }, phone: '1-770-736-8031 x56442', website: 'hildegard.org', company: { name: 'Romaguera-Crona', catchPhrase: 'Multi-layered client-server neural-net', bs: 'harness real-time e-markets' } }, { id: 2, name: 'Ervin Howell', username: 'Antonette', email: 'Shanna@melissa.tv', address: { street: 'Victor Plains', suite: 'Suite 879', city: 'Wisokyburgh', zipcode: '90566-7771', geo: [Object] }, phone: '010-692-6593 x09125', website: 'anastasia.net', company: { name: 'Deckow-Crist', catchPhrase: 'Proactive didactic contingency', bs: 'synergize scalable supply-chains' } } ]
这意味着您已成功使用核心 Node.js 库发出 GET
请求。
您使用的 get()
方法是 Node.js 提供的一种方便的方法,因为 GET
请求是一种非常常见的请求类型。 Node.js 提供了一个 request()
方法来发出任何类型的请求。 接下来,本教程将研究如何使用 request()
发出 GET
请求。
使用 request()
发出请求
request()
方法支持多个函数签名。 您将在后续示例中使用这个:
https.request(URL_String, Options_Object, Callback_Function) { Action }
第一个参数是一个带有 API 端点的字符串。 第二个参数是一个 JavaScript 对象,其中包含请求的所有选项。 最后一个参数是处理响应的回调函数。
为名为 getRequestWithRequest.js
的新模块创建一个新文件:
nano getRequestWithRequest.js
您将编写的代码类似于您之前编写的 getRequestWithGet.js
模块。 首先,导入https
模块:
请求/getRequestWithRequest.js
const https = require('https');
接下来,创建一个包含 method
键的新 JavaScript 对象:
请求/getRequestWithRequest.js
const https = require('https'); const options = { method: 'GET' };
此对象中的 method
键将告诉 request()
函数请求使用的 HTTP 方法。
接下来,在您的代码中发出请求。 以下代码块突出显示了与使用 get()
方法发出的请求不同的代码。 在您的编辑器中,输入以下所有行:
请求/getRequestWithRequest.js
... let request = https.request('https://jsonplaceholder.typicode.com/users?_limit=2', options, (res) => { if (res.statusCode !== 200) { console.error(`Did not get an OK from the server. Code: ${res.statusCode}`); res.resume(); return; } let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('close', () => { console.log('Retrieved all data'); console.log(JSON.parse(data)); }); }); request.end(); request.on('error', (err) => { console.error(`Encountered an error trying to make a request: ${err.message}`); });
要使用 request()
发出请求,请在第一个参数中提供 URL,在第二个参数中提供带有 HTTP 选项的对象,并在第三个参数中提供处理响应的回调。
您之前创建的 options
变量是第二个参数,告诉 Node.js 这是一个 GET
请求。 回调与您第一次编写它时相比没有变化。
您还可以调用 request
变量的 end()
方法。 这是使用request()
函数时必须调用的重要方法。 它完成了请求,允许它被发送。 如果你不调用它,程序永远不会完成,因为 Node.js 会认为你还有数据要添加到请求中。
使用 CTRL+X
保存并退出 nano
,或使用文本编辑器进行等效操作。
在您的终端中运行此程序:
node getRequestWithRequest.js
您将收到此输出,与第一个模块相同:
OutputRetrieved all data [ { id: 1, name: 'Leanne Graham', username: 'Bret', email: 'Sincere@april.biz', address: { street: 'Kulas Light', suite: 'Apt. 556', city: 'Gwenborough', zipcode: '92998-3874', geo: [Object] }, phone: '1-770-736-8031 x56442', website: 'hildegard.org', company: { name: 'Romaguera-Crona', catchPhrase: 'Multi-layered client-server neural-net', bs: 'harness real-time e-markets' } }, { id: 2, name: 'Ervin Howell', username: 'Antonette', email: 'Shanna@melissa.tv', address: { street: 'Victor Plains', suite: 'Suite 879', city: 'Wisokyburgh', zipcode: '90566-7771', geo: [Object] }, phone: '010-692-6593 x09125', website: 'anastasia.net', company: { name: 'Deckow-Crist', catchPhrase: 'Proactive didactic contingency', bs: 'synergize scalable supply-chains' } } ]
您现在已经使用 request()
方法发出 GET
请求。 了解此功能很重要,因为它允许您以 get()
方法无法自定义的方式自定义请求,例如使用其他 HTTP 方法发出请求。
接下来,您将使用 request()
函数配置和自定义您的请求。
第 2 步 — 配置 HTTP request()
选项
request()
函数允许您发送 HTTP 请求,而无需在第一个参数中指定 URL。 在这种情况下,URL 将包含在 options
对象中,并且 request()
将具有以下函数签名:
https.request(Options_Object, Callback_Function) { Action }
在此步骤中,您将使用此功能将 request()
配置为 options
对象。
Node.js 允许您在传递给请求的 options
对象中输入 URL。 要尝试此操作,请重新打开 getRequestWithRequest.js
文件:
nano getRequestWithRequest.js
从 request()
调用中删除 URL,以便唯一的参数是 options
变量和回调函数:
请求/getRequestWithRequest.js
const https = require('https'); const options = { method: 'GET', }; let request = https.request(options, (res) => { ...
现在将以下属性添加到 options
对象:
请求/getRequestWithRequest.js
const https = require('https'); const options = { host: 'jsonplaceholder.typicode.com', path: '/users?_limit=2', method: 'GET' }; let request = https.request(options, (res) => { ...
您有两个属性——host
和 path
,而不是一个字符串 URL。 host
是您正在访问的服务器的域名或 IP 地址。 路径是域名后面的所有内容,包括查询参数(问号后面的值)。
选项对象可以保存进入请求的其他有用数据。 例如,您可以在选项中提供请求标头。 标头通常会发送有关请求的元数据。
当开发人员创建 API 时,他们可能会选择支持不同的数据格式。 一个 API 端点可能能够以 JSON、CSV 或 XML 格式返回数据。 在这些 API 中,服务器可能会查看 Accept
标头以确定正确的响应类型。
Accept
标头指定用户可以处理的数据类型。 虽然这些示例中使用的 API 仅返回 JSON,但您可以将 Accept
标头添加到您的请求中,以明确声明您需要 JSON。
添加以下代码行以附加 Accept
标头:
请求/getRequestWithRequest.js
const https = require('https'); const options = { host: 'jsonplaceholder.typicode.com', path: '/users?_limit=2', method: 'GET', headers: { 'Accept': 'application/json' } };
通过添加标头,您已经了解了在 Node.js HTTP 请求中发送的四个最流行的选项:host
、path
、method
和 [X145X ]。 Node.js 支持更多选项; 您可以在 官方 Node.js 文档 中阅读更多信息以获取更多信息。
输入 CTRL+X
保存文件并退出 nano
。
接下来,再次运行您的代码以仅使用选项发出请求:
node getRequestWithRequest.js
结果将与您之前的运行相同:
OutputRetrieved all data [ { id: 1, name: 'Leanne Graham', username: 'Bret', email: 'Sincere@april.biz', address: { street: 'Kulas Light', suite: 'Apt. 556', city: 'Gwenborough', zipcode: '92998-3874', geo: [Object] }, phone: '1-770-736-8031 x56442', website: 'hildegard.org', company: { name: 'Romaguera-Crona', catchPhrase: 'Multi-layered client-server neural-net', bs: 'harness real-time e-markets' } }, { id: 2, name: 'Ervin Howell', username: 'Antonette', email: 'Shanna@melissa.tv', address: { street: 'Victor Plains', suite: 'Suite 879', city: 'Wisokyburgh', zipcode: '90566-7771', geo: [Object] }, phone: '010-692-6593 x09125', website: 'anastasia.net', company: { name: 'Deckow-Crist', catchPhrase: 'Proactive didactic contingency', bs: 'synergize scalable supply-chains' } } ]
由于 API 可能因提供商而异,因此熟悉 options
对象是适应其不同要求的关键,其中数据类型和标头是一些最常见的变化。
到目前为止,您只完成了 GET
请求来检索数据。 接下来,您将使用 Node.js 发出 POST
请求,以便将数据上传到服务器。
第 3 步 — 发出 POST
请求
当您将数据上传到服务器或希望服务器为您创建数据时,您通常会发送 POST
请求。 在本节中,您将在 Node.js 中创建一个 POST
请求。 您将请求在 users
API 中创建新用户。
尽管与 GET
的方法不同,但在编写 POST
请求时,您将能够重用先前请求中的代码。 但是,您必须进行以下调整:
- 将
options
对象中的方法改为POST
- 添加标题以说明您正在上传 JSON
- 检查状态码以确认用户已创建
- 上传新用户的数据
要进行这些更改,首先创建一个名为 postRequest.js
的新文件。 在 nano
或其他文本编辑器中打开此文件:
nano postRequest.js
首先导入 https
模块并创建一个 options
对象:
请求/postRequest.js
const https = require('https'); const options = { host: 'jsonplaceholder.typicode.com', path: '/users', method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json; charset=UTF-8' } };
您更改 path
以匹配 POST
请求所需的内容。 您还将 method
更新为 POST
。 最后,您在选项 Content-Type
中添加了一个新标题。 此标头告诉服务器您要上传的数据类型。 在这种情况下,您将使用 UTF-8 编码 上传 JSON 数据。
接下来,使用 request()
函数发出请求。 这类似于您发出 GET
请求的方式,但现在您查找的状态码与 200 不同。 将以下行添加到代码的末尾:
请求/postRequest.js
... const request = https.request(options, (res) => { if (res.statusCode !== 201) { console.error(`Did not get a Created from the server. Code: ${res.statusCode}`); res.resume(); return; } let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('close', () => { console.log('Added new user'); console.log(JSON.parse(data)); }); });
突出显示的代码行检查状态代码是否为 201。 201 状态码用于表示服务器创建了资源。
这个 POST
请求是为了创建一个新用户。 对于此 API,您需要上传用户详细信息。 创建一些用户数据并将其与您的 POST
请求一起发送:
请求/postRequest.js
... const requestData = { name: 'New User', username: 'digitalocean', email: 'user@digitalocean.com', address: { street: 'North Pole', city: 'Murmansk', zipcode: '12345-6789', }, phone: '555-1212', website: 'digitalocean.com', company: { name: 'DigitalOcean', catchPhrase: 'Welcome to the developer cloud', bs: 'cloud scale security' } }; request.write(JSON.stringify(requestData));
您首先创建了 requestData
变量,它是一个包含用户数据的 JavaScript 对象。 您的请求不包括 id
字段,因为服务器通常会在保存新数据时生成这些字段。
接下来使用 request.write()
函数,它接受字符串或 缓冲区对象 与请求一起发送。 由于您的 requestData
变量是一个对象,因此您使用了 JSON.stringify
函数将其转换为字符串。
要完成此模块,请结束请求并检查错误:
请求/postRequest.js
... request.end(); request.on('error', (err) => { console.error(`Encountered an error trying to make a request: ${err.message}`); });
在使用 end()
函数之前写入数据很重要。 end()
函数告诉 Node.js 没有更多数据要添加到请求中并发送它。
按 CTRL+X
保存并退出 nano
。
运行此程序以确认已创建新用户:
node postRequest.js
将显示以下输出:
OutputAdded new user { name: 'New User', username: 'digitalocean', email: 'user@digitalocean.com', address: { street: 'North Pole', city: 'Murmansk', zipcode: '12345-6789' }, phone: '555-1212', website: 'digitalocean.com', company: { name: 'DigitalOcean', catchPhrase: 'Welcome to the developer cloud', bs: 'cloud scale security' }, id: 11 }
输出确认请求成功。 API 返回上传的用户数据以及分配给它的 ID。
现在您已经学会了如何发出 POST
请求,您可以在 Node.js 中将数据上传到服务器。 接下来,您将尝试 PUT
请求,这是一种用于更新服务器中数据的方法。
第 4 步 — 发出 PUT
请求
开发人员发出 PUT
请求将数据上传到服务器。 虽然这可能类似于 POST
请求,但 PUT
请求具有不同的功能。 PUT
请求是 幂等 — 你可以多次运行 PUT
请求,它会得到相同的结果。
实际上,您编写的代码类似于 POST
请求。 您设置选项、提出请求、编写要上传的数据并验证响应。
要尝试此操作,您将创建一个 PUT
请求来更新第一个用户的用户名。
由于代码类似于 POST
请求,您将使用该模块作为此模块的基础。 将 postRequest.js
复制到一个新文件 putRequest.js
中:
cp postRequest.js putRequest.js
现在在文本编辑器中打开 putRequest.js
:
nano putRequest.js
进行这些突出显示的更改,以便向 https://jsonplaceholder.typicode.com/users/1
发送 PUT
请求:
请求/putRequest.js
const https = require('https'); const options = { host: 'jsonplaceholder.typicode.com', path: '/users/1', method: 'PUT', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json; charset=UTF-8' } }; const request = https.request(options, (res) => { if (res.statusCode !== 200) { console.error(`Did not get an OK from the server. Code: ${res.statusCode}`); res.resume(); return; } let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('close', () => { console.log('Updated data'); console.log(JSON.parse(data)); }); }); const requestData = { username: 'digitalocean' }; request.write(JSON.stringify(requestData)); request.end(); request.on('error', (err) => { console.error(`Encountered an error trying to make a request: ${err.message}`); });
首先更改 options
对象的 path
和 method
属性。 在这种情况下,path
标识您要更新的用户。 当您发出请求时,您检查响应代码是否为 200,这意味着请求正常。 您现在上传的数据仅包含您正在更新的属性。
使用 CTRL+X
保存并退出 nano
。
现在在终端中执行这个 Node.js 程序:
node putRequest.js
您将收到以下输出:
OutputUpdated data { username: 'digitalocean', id: 1 }
您发送了 PUT
请求以更新现有用户。
到目前为止,您已经学习了如何检索、添加和更新数据。 为了给我们提供通过 API 管理数据的完整命令,您接下来将发出 DELETE
请求以从服务器中删除数据。
第 5 步 — 发出 DELETE
请求
DELETE
请求用于从服务器中删除数据。 它可以有一个请求主体,但大多数 API 往往不需要它们。 此方法用于从服务器中删除整个对象。 在本节中,您将使用 API 删除用户。
您将编写的代码类似于 GET
请求的代码,因此请使用该模块作为此模块的基础。 将 getRequestWithRequest.js
文件复制到新的 deleteRequest.js
文件中:
cp getRequestWithRequest.js deleteRequest.js
用 nano
打开 deleteRequest.js
:
nano deleteRequest.js
现在修改突出显示部分的代码,以便您可以删除 API 中的第一个用户:
请求/putRequest.js
const https = require('https'); const options = { host: 'jsonplaceholder.typicode.com', path: '/users/1', method: 'DELETE', headers: { 'Accept': 'application/json', } }; const request = https.request(options, (res) => { if (res.statusCode !== 200) { console.error(`Did not get an OK from the server. Code: ${res.statusCode}`); res.resume(); return; } let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('close', () => { console.log('Deleted user'); console.log(JSON.parse(data)); }); }); request.end(); request.on('error', (err) => { console.error(`Encountered an error trying to make a request: ${err.message}`); });
对于本模块,首先将选项对象的 path
属性更改为要删除的资源 — 第一个用户。 然后将方法更改为 DELETE
。
按 CTRL+X
保存并退出此文件。
运行此模块以确认其工作。 在终端中输入以下命令:
node deleteRequest.js
该程序将输出以下内容:
OutputDeleted user {}
虽然 API 不返回响应正文,但您仍然收到 200 响应,因此请求正常。
您现在已经学习了如何使用 Node.js 核心模块发出 DELETE
请求。
结论
在本教程中,您在 Node.js 中发出了 GET
、POST
、PUT
和 DELETE
请求。 没有安装任何库; 这些请求是使用标准 https
模块发出的。 虽然可以使用 get()
函数发出 GET
请求,但所有其他 HTTP 方法都是通过 request()
方法完成的。
您编写的代码是为一个公开可用的测试 API 编写的。 但是,您编写请求的方式适用于所有类型的 API。 如果您想了解有关 API 的更多信息,请查看我们的 API 主题页面。 有关使用 Node.js 进行开发的更多信息,请返回 如何在 Node.js 中编写代码系列。