作者选择了 COVID-19 救援基金作为 Write for Donations计划的一部分,接受捐款。
介绍
当您在浏览器中查看网页时,您正在向互联网上的另一台计算机提出请求,然后向您提供网页作为响应.您通过互联网交谈的计算机是 web server. Web 服务器从客户端(如您的浏览器)接收 HTTP 请求,并提供 HTTP 响应,如 HTML 页面或 API 的 JSON。
该软件通常分为两类:前端和后端。 Front-end code 关心内容的呈现方式,如导航栏的颜色和文本风格。 Back-end code 关心数据的交换、处理和存储方式。
Node.js允许开发人员使用 JavaScript来编写后端代码,尽管传统上它被用在浏览器中编写前端代码。
在本教程中,您将学习如何使用 Node.js 中包含的 http
模块构建 Web 服务器,您将构建可以返回 JSON 数据, CSV 文件和 HTML 网页的 Web 服务器。
简化使用 DigitalOcean App Platform部署 Node.js 应用程序。
前提条件
- 确保将Node.js安装在您的开发机器上。 此教程使用Node.js版本的10.19. 要在 macOS 或 Ubuntu 18.04 上安装,请遵循 [如何在 macOS (https://andsky.com/tech/tutorials/how-to-install-node-js-and-create-a-local-development-environment-on-macos) 上安装节点并创建本地开发环境(https://andsky.com/tech/tutorials/how-to-install-node-js-on-ubuntu-18-04)中的步骤,或使用 [如何在 Ubuntu 18.04 (https://andsky.com/tech/tutorials/how-to-install-node-js-on-ubuntu-18-04 上安装节点.js] 的 PPA** 部分。
*Node.js平台支持从框中创建网络服务器. 要开始,要确定你熟悉"节点"(Node.js)的基本内容. 您可以在
如何在节点. js
(https://andsky.com/tech/tutorials/how-to-write-and-run-your-first-program-in-node-js) 上审查我们的指南。 - 联合国 我们还利用一个同步编程,用于我们的一个部分。 如果你不熟悉节点的同步编程. js 或用于与文件互动的 " fs " 模块,您可以通过我们关于[如何在Node.js (https://andsky.com/tech/tutorials/how-to-write-asynchronous-code-in-node-js)中写出同步代码]的文章学习更多内容。 .
第1步:创建基本的HTTP服务器
让我们先创建一个向用户返回简单文本的服务器,这将涵盖设置服务器所需的关键概念,这将为返回更复杂的数据格式(如JSON)提供必要的基础。
首先,我们需要设置一个易于访问的编码环境来执行我们的练习,以及文章中的其他人,在终端中创建一个名为第一服务器
的文件夹:
1mkdir first-servers
然后输入这个文件夹:
1cd first-servers
现在,创建将容纳代码的文件:
1touch hello.js
在文本编辑器中打开文件,我们将使用nano
,因为它在终端中可用:
1nano hello.js
我們開始下載所有 Node.js 安裝程式的標準「http」模組,並將下列行添加到「hello.js」中:
1[label first-servers/hello.js]
2const http = require("http");
如果您想了解更多关于 Node.js 中的模块,请参阅我们的 如何创建 Node.js 模块文章。
我们的下一步将是定义两个常数,主机和端口,我们的服务器将被绑定到:
1[label first-servers/hello.js]
2...
3const host = 'localhost';
4const port = 8000;
如前所述,网页服务器接受浏览器和其他客户端的请求。我们可以通过输入域名来与网页服务器进行交互,该域名由 DNS 服务器转换为 IP 地址。 IP 地址是一种在网络上识别机器的数字的独特序列,如互联网。 有关域名概念的更多信息,请参阅我们的文章。
值Localhost
是一个专门的私人地址,计算机用来引用自己. 它通常相当于内部IP地址127.0.0.1
,它只可用于本地计算机,而不是任何我们已连接的本地网络或互联网。
端口是服务器使用为我们的IP地址的终端点或门
的数字,在我们的示例中,我们将为我们的Web服务器使用端口8000
。
当我们将我们的服务器连接到该主机和端口时,我们将能够通过访问本地浏览器的http://localhost:8000’访问我们的服务器。
让我们添加一个特殊的函数,在 Node.js 中我们称之为 request listener. 这个函数旨在处理传入的 HTTP 请求并返回 HTTP 响应. 这个函数必须有两个参数,一个请求对象和一个响应对象。
我们希望我们的第一个服务器每当有人访问它时返回这个消息:我的第一个服务器!
接下来就添加这个函数:
1[label first-servers/hello.js]
2...
3
4const requestListener = function (req, res) {
5 res.writeHead(200);
6 res.end("My first server!");
7};
例如,如果我们创建了一个请求倾听函数来返回一份书籍列表,我们很可能将其命名为listBooks()
。
Node.js 中的所有请求倾听函数都接受两个参数: req
和 res
(如果我们想要的话,我们可以用不同的名称命名它们)。
第一行res.writeHead(200);
设置了响应的HTTP状态代码。HTTP状态代码表示服务器处理了HTTP请求的效果。在这种情况下,状态代码200
相当于OK
。如果你有兴趣了解您的Web服务器可以返回的各种HTTP状态代码,那么我们关于如何解决常见的HTTP错误代码(How To Troubleshoot Common HTTP Error Codes)的指南(https://andsky.com/tech/tutorials/how-to-troubleshoot-common-http-error-codes)是一个很好的开始。
函数的下一个行,res.end
(我的第一个服务器!
);`将HTTP响应写回请求的客户端,该函数返回服务器必须返回的任何数据,在这种情况下,它返回文本数据。
最后,我们现在可以创建我们的服务器并使用我们的请求倾听器:
1[label first-servers/hello.js]
2...
3
4const server = http.createServer(requestListener);
5server.listen(port, host, () => {
6 console.log(`Server is running on http://${host}:${port}`);
7});
保存和退出nano
通过按CTRL+X
。
在第一行中,我们通过http
模块的createServer()
函数创建一个新的服务器
对象,该服务器接受 HTTP 请求,并将其传递到我们的requestListener()
函数。
在我们创建服务器后,我们必须将其绑定到一个网络地址,我们使用server.listen()
方法来做到这一点,它接受三个参数:port
,host
,以及一个呼叫函数(https://andsky.com/tech/tutorials/how-to-write-asynchronous-code-in-node-js# asynchronous-programming-with-callbacks),当服务器开始聆听时会启动。
所有这些论点都是可选的,但最好明确说明我们希望使用哪个端口和主机. 部署 Web 服务器到不同的环境时,需要知道它正在运行的端口和主机来设置负载平衡或 DNS名称。
回调函数将消息记录到我们的控制台,以便我们可以知道服务器何时开始聆听连接。
注意:即使requestListener()
不使用req
对象,它仍然必须是函数的第一个参数。
有了不到十五行代码,我们现在有一个Web服务器,让我们在行动中看到它,并通过运行该程序对其进行终端测试:
1node hello.js
在控制台中,我们将看到这个输出:
1[secondary_label Output]
2Server is running on http://localhost:8000
请注意,提示消失,这是因为Node.js服务器是一个漫长的运行过程,它只有在遇到导致它崩溃和停止的错误时才会退出,或者如果我们停止Node.js服务器运行的过程。
在一个单独的终端窗口中,我们将使用 cURL的CLI工具与服务器进行通信,以便将数据传输到和从网络中。
1curl http://localhost:8000
当我们按下ENTER
,我们的终端将显示以下输出:
1[secondary_label Output]
2My first server!
我们现在已经设置了一个服务器,并获得了我们的第一个服务器响应。
让我们看看当我们测试我们的服务器时发生了什么。 使用cURL,我们向服务器发送了一个GET
请求,地址为http://localhost:8000
。 我们的Node.js服务器听取了来自该地址的连接。 服务器将该请求传递到requestListener()
函数。 该函数返回了文本数据,状态代码为200
。 然后,服务器将该响应发送回cURL,在我们的终端中显示了消息。
在我们继续之前,让我们通过按CTRL+C
来退出我们的运行服务器,这会中断我们的服务器的执行,让我们回到命令行提示。
在我们访问的大多数网站或我们使用的API中,服务器的响应很少以简单的文本进行。我们将HTML页面和JSON数据作为常见的响应格式。
步骤 2 – 返回不同类型的内容
我們從網頁伺服器返回的回應可以採取各種格式. JSON 和 HTML 之前提到,我們也可以返回其他文本格式,如 XML 和 CSV. 最後,網頁伺服器可以返回非文本資料,如 PDF, zipped 檔案,音頻和視頻。
在本文中,除了我们刚刚返回的简单文本外,您还会学习如何返回以下类型的数据:
- JSON * CSV * HTML
这三种数据类型都是基于文本的,是用于在网络上提供内容的流行的格式. 许多服务器侧开发语言和工具都支持返回这些不同的数据类型。
- 将我们的 HTTP 响应中的
内容类型
标题设置为相应的值 2. 确保res.end()
以正确的格式获取数据。
让我们用一些例子来看到这一点,我们将在本节中写的代码和以后的代码与我们之前写的代码有很多相似之处.大多数的变化都存在于RequestListener()
函数中。
创建一个名为html.js
的新文件. 这个文件将在以后用于返回HTML文本的HTTP响应. 我们将把模板代码放在这里,并将其复制到返回不同类型的其他服务器。
在终端中,输入以下内容:
1touch html.js
现在在文本编辑器中打开此文件:
1nano html.js
让我们复制模板代码
。在nano
中输入这个:
1[label first-servers/html.js]
2const http = require("http");
3
4const host = 'localhost';
5const port = 8000;
6
7const requestListener = function (req, res) {};
8
9const server = http.createServer(requestListener);
10server.listen(port, host, () => {
11 console.log(`Server is running on http://${host}:${port}`);
12});
保存和退出html.js
用CTRL+X
,然后返回终端。
现在让我们将这个文件复制成两个新的文件,第一个文件将是返回HTTP响应中的CSV数据:
1cp html.js csv.js
第二个文件将返回服务器中的 JSON 响应:
1cp html.js json.js
剩下的文件将用于以后的练习:
1cp html.js htmlFile.js
2cp html.js routes.js
我们现在已经设置了继续我们的练习,让我们从返回JSON开始。
服务 JSON
JavaScript Object Notation,通常称为JSON,是一种基于文本的数据交换格式,如其名称所示,它源自JavaScript对象,但它是语言独立的,这意味着它可以被任何可以解析其语法的编程语言使用。
JSON 通常被 APIs 用来接收和返回数据,其受欢迎性是由于其数据传输大小低于以前的数据交换标准(如 XML),以及现有的工具,允许程序无需过度努力分析它们。
打开json.js
文件,使用nano
:
1nano json.js
让我们修改requestListener()
函数以返回所有 JSON 响应的适当标题,以此方式更改突出的行:
1[label first-servers/json.js]
2...
3const requestListener = function (req, res) {
4 res.setHeader("Content-Type", "application/json");
5};
6...
res.setHeader()
方法将 HTTP 标题添加到响应中. HTTP 标题是可以附加到请求或响应的额外信息. res.setHeader()
方法需要两个参数:标题的名称和值。
内容类型
标题用于表示与请求或响应一起发送的数据的格式,也称为媒体类型。
现在,让我们将 JSON 内容返回给用户。修改 json.js
以便它看起来像这样:
1[label first-servers/json.js]
2...
3const requestListener = function (req, res) {
4 res.setHeader("Content-Type", "application/json");
5 res.writeHead(200);
6 res.end(`{"message": "This is a JSON response"}`);
7};
8...
与之前一样,我们通过返回200
的状态代码告知用户他们的请求成功,这次在response.end()
呼叫中,我们的字符串参数包含有效的JSON。
保存和退出json.js
按CTRL+X
。现在,让我们用节点
命令运行服务器:
1node json.js
在另一个终端中,让我们使用cURL来到达服务器:
1curl http://localhost:8000
当我们点击进入
时,我们会看到以下结果:
1[secondary_label Output]
2{"message": "This is a JSON response"}
现在我们已经成功返回了JSON响应,就像我们创建应用程序的许多流行的API一样. 请确保使用CTRL+C
退出运行服务器,以便我们可以返回标准终端提示。
服务 CSV
Comma Separated Values (CSV) 文件格式是一个常用来提供表数据的文本标准,在大多数情况下,每个行都被新行分开,而行中的每个项目都被小行分开。
在我们的工作空间中,使用文本编辑器打开csv.js
文件:
1nano csv.js
让我们将以下行添加到我们的requestListener()
函数中:
1[label first-servers/csv.js]
2...
3const requestListener = function (req, res) {
4 res.setHeader("Content-Type", "text/csv");
5 res.setHeader("Content-Disposition", "attachment;filename=oceanpals.csv");
6};
7...
这一次,我们的内容类型
表示正在返回一个CSV文件,其值是text/csv
。我们添加的第二个标题是Content-Disposition
。
当我们返回 CSV 响应时,大多数现代浏览器会自动下载该文件,即使没有设置内容配置
标题,但是当返回 CSV 文件时,我们仍然应该添加此标题,因为它允许我们设置 CSV 文件的名称。
让我们在 HTTP 响应中写入 CSV 数据:
1[label first-servers/csv.js]
2...
3const requestListener = function (req, res) {
4 res.setHeader("Content-Type", "text/csv");
5 res.setHeader("Content-Disposition", "attachment;filename=oceanpals.csv");
6 res.writeHead(200);
7 res.end(`id,name,email\n1,Sammy Shark,[email protected]`);
8};
9...
与之前一样,我们与我们的响应返回200
/OK
状态。这次,我们的呼叫到res.end()
有一个字符串,这是一个有效的CSV。 字符串将每个列中的值分开,新的行字符(n
)将行分开。
我们将在浏览器中测试这个服务器. 保存csv.js
,然后用CTRL+X
退出编辑器。
使用 Node.js 命令运行服务器:
1node csv.js
在另一个终端中,让我们使用cURL来到达服务器:
1curl http://localhost:8000
控制台将显示这些:
1[secondary_label Output]
2id,name,email
31,Sammy Shark,[email protected]
如果我们在浏览器中访问http://localhost:8000
,则会下载一个 CSV 文件,其文件名为oceanpals.csv
。
使用CTRL+C
退出运行服务器,返回标准终端提示。
返回 JSON 和 CSV 后,我们涵盖了对 API 很受欢迎的两个案例,让我们再来谈谈我们如何返回用户在浏览器中查看的网站的数据。
HTML 服务
HTML,超文本标记语言,是当我们希望用户通过网页浏览器与我们的服务器进行交互时使用的最常见的格式。它是为了构建网页内容而创建的。
让我们用我们的文本编辑器重新打开html.js
:
1nano html.js
更改requestListener()
函数以返回 HTML 响应的适当Content-Type
标题:
1[label first-servers/html.js]
2...
3const requestListener = function (req, res) {
4 res.setHeader("Content-Type", "text/html");
5};
6...
现在,让我们将HTML内容归还给用户,然后将突出的行添加到html.js
,以便它看起来像这样:
1[label first-servers/html.js]
2...
3const requestListener = function (req, res) {
4 res.setHeader("Content-Type", "text/html");
5 res.writeHead(200);
6 res.end(`<html><body><h1>This is HTML</h1></body></html>`);
7};
8...
我们首先添加了HTTP状态代码,然后我们用含有有效HTML的字符串参数调用response.end()
。当我们在浏览器中访问我们的服务器时,我们会看到一个HTML页面,其中包含一个标题标签This is HTML
。
让我们通过按CTRL+X
来保存和退出,现在,让我们用节点
命令运行服务器:
1node html.js
我们会看到服务器在 http://localhost:8000
上运行,当我们的程序启动时。
现在进入浏览器并访问http://localhost:8000
。我们的页面将看起来像这样:
让我们用CTRL+C
离开运行服务器,然后回到标准终端提示。
HTML 通常会被写成一个文件,与服务器侧代码分开,例如我们的 Node.js 程序。
步骤3 — 从文件中服务一个HTML页面
我们可以将HTML作为Node.js中的字符串服务给用户,但最好是我们加载HTML文件并服务其内容。以这种方式,随着HTML文件的增长,我们不必在Node.js代码中维持长的字符串,保持更简洁,并允许我们独立工作在我们的网站的每个方面。
为了服务 HTML 文件,我们用 fs
模块加载 HTML 文件,并在编写我们的 HTTP 响应时使用其数据。
首先,我们将创建一个HTML文件,网页服务器将返回它。
1touch index.html
现在在文本编辑器中打开index.html
:
1nano index.html
我们的网页将是最小的. 它将有橙色背景,并将显示一些问候文本在中心. 添加此代码到文件:
1[label first-servers/index.html]
2<!DOCTYPE html>
3
4<head>
5 <title>My Website</title>
6 <style>
7 *,
8 html {
9 margin: 0;
10 padding: 0;
11 border: 0;
12 }
13
14 html {
15 width: 100%;
16 height: 100%;
17 }
18
19 body {
20 width: 100%;
21 height: 100%;
22 position: relative;
23 background-color: rgb(236, 152, 42);
24 }
25
26 .center {
27 width: 100%;
28 height: 50%;
29 margin: 0;
30 position: absolute;
31 top: 50%;
32 left: 50%;
33 transform: translate(-50%, -50%);
34 color: white;
35 font-family: "Trebuchet MS", Helvetica, sans-serif;
36 text-align: center;
37 }
38
39 h1 {
40 font-size: 144px;
41 }
42
43 p {
44 font-size: 64px;
45 }
46 </style>
47</head>
48
49<body>
50 <div class="center">
51 <h1>Hello Again!</h1>
52 <p>This is served from a file</p>
53 </div>
54</body>
55
56</html>
这个单一的网页显示了两行文本:再见!
和这是从文件中提供的
。 这些行显示在网页的中心,一个在对方上面。 第一行文本显示在一个标题中,这意味着它会大。 第二行文本会显得稍微小一些。 所有文本将显示为白色,网页的背景是橙色的。
虽然这不是本文或系列的范围,但如果您有兴趣了解更多有关HTML、CSS和其他前端Web技术的信息,则可以参阅《Mozilla开始使用Web》指南。
这就是我们需要的HTML,所以用CTRL+X来保存和退出文件,我们现在可以转到服务器代码。
对于这个练习,我们将工作在 htmlFile.js
. 用文本编辑器打开它:
1nano htmlFile.js
由于我们必须阅读一个文件,让我们从导入fs
模块开始:
1[label first-servers/htmlFile.js]
2const http = require("http");
3const fs = require('fs').promises;
4...
这个模块包含一个readFile()
函数,我们将使用它来加载HTML文件。我们根据现代JavaScript的最佳做法导入了承诺变体。我们使用承诺作为其语法比回复更简洁,如果我们将fs
分配到require('fs')
,我们将不得不使用它。 要了解更多关于非同步编程的最佳做法,您可以阅读我们的如何在Node.js中编写非同步代码
指南。
我们希望我们的HTML文件在用户要求我们的系统时被读取,让我们开始修改‘requestListener()’来读取该文件:
1[label first-servers/htmlFile.js]
2...
3const requestListener = function (req, res) {
4 fs.readFile(__dirname + "/index.html")
5};
6...
我们使用fs.readFile()
方法来加载文件,它的参数有__dirname +
/index.html``. 特殊的变量 __dirname
具有运行 Node.js 代码的绝对路径,然后添加/index.html
,这样我们就可以加载我们之前创建的 HTML 文件。
现在让我们在加载后返回 HTML 页面:
1[label first-servers/htmlFile.js]
2...
3const requestListener = function (req, res) {
4 fs.readFile(__dirname + "/index.html")
5 .then(contents => {
6 res.setHeader("Content-Type", "text/html");
7 res.writeHead(200);
8 res.end(contents);
9 })
10};
11...
如果fs.readFile()
承诺成功解决,它将返回其数据. 我们使用then()
方法来处理此案。
我们首先将内容类型
标题设置为文本/html
,以告知客户端我们正在返回HTML数据,然后我们编写状态代码,表示请求成功,最后我们将我们加载的HTML页面发送给客户端,数据包含在内容
变量中。
fs.readFile()
方法有时会失败,所以当我们收到错误时,我们应该处理此案子。
1[label first-servers/htmlFile.js]
2...
3const requestListener = function (req, res) {
4 fs.readFile(__dirname + "/index.html")
5 .then(contents => {
6 res.setHeader("Content-Type", "text/html");
7 res.writeHead(200);
8 res.end(contents);
9 })
10 .catch(err => {
11 res.writeHead(500);
12 res.end(err);
13 return;
14 });
15};
16...
保存文件并输出nano
用CTRL+X
。
当一个承诺遇到错误时,它会被拒绝。我们使用catch()
方法来处理这种情况。它接受fs.readFile()
返回的错误,将状态代码设置为500
,表示出现了内部错误,并将错误返回给用户。
使用node
命令运行我们的服务器:
1node htmlFile.js
在 Web 浏览器中,请访问 http://localhost:8000
. 您将看到此页面:
您现在已经从服务器返回了一个HTML页面给用户,您可以用CTRL+C离开运行服务器,当您这样做时,您将看到终端提示返回。
在制作中写代码时,你可能不希望每次收到HTTP请求时都加载HTML页面,虽然这个HTML页面大小大约为800字节,但更复杂的网站大小可能为megabyte。大文件可能需要一段时间才能加载。如果你的网站预计有大量的流量,最好在启动时加载HTML文件并保存其内容。
为了展示这种方法,让我们看看我们如何重新设计我们的服务器,以便更高效和可扩展。
有效地服务HTML
在此步骤中,我们不会在每个请求中加载HTML,而是将其加载一次,请求将返回我们在启动时加载的数据。
在终端中,使用文本编辑器重新打开 Node.js 脚本:
1nano htmlFile.js
让我们先在创建requestListener()
函数之前添加一个新的变量:
1[label first-servers/htmlFile.js]
2...
3let indexFile;
4
5const requestListener = function (req, res) {
6...
当我们运行这个程序时,这个变量将包含HTML文件的内容。
现在,让我们重新调整requestListener()
函数,而不是加载文件,它现在将返回indexFile
的内容:
1[label first-servers/htmlFile.js]
2...
3const requestListener = function (req, res) {
4 res.setHeader("Content-Type", "text/html");
5 res.writeHead(200);
6 res.end(indexFile);
7};
8...
接下来,我们将文件阅读逻辑从requestListener()
函数转移到我们的服务器启动。
1[label first-servers/htmlFile.js]
2...
3
4const server = http.createServer(requestListener);
5
6fs.readFile(__dirname + "/index.html")
7 .then(contents => {
8 indexFile = contents;
9 server.listen(port, host, () => {
10 console.log(`Server is running on http://${host}:${port}`);
11 });
12 })
13 .catch(err => {
14 console.error(`Could not read index.html file: ${err}`);
15 process.exit(1);
16 });
保存文件并输出nano
用CTRL+X
。
读取该文件的代码类似于我们在第一次尝试中所写的代码,但是当我们成功读取该文件时,我们现在将内容保存到我们的全球indexFile
变量中,然后我们用listen()
方法启动服务器,关键是该文件在运行服务器之前被加载,因此requestListener()
函数肯定会返回HTML页面,因为indexFile
不再是一个空变量。
我们的错误处理器也发生了变化. 如果文件无法加载,我们会捕捉错误并将其打印到我们的控制台. 然后在不启动服务器的情况下,我们会离开 Node.js 程序使用 exit()
函数。
现在我们已经创建了不同的网页服务器,将不同类型的数据返回给用户。 到目前为止,我们还没有使用任何请求数据来确定应该返回的内容。
步骤 4 — 使用 HTTP 请求对象管理路线
我们访问的大多数网站或我们使用的 API 通常有多个端点,以便我们可以访问各种资源. 一个很好的例子是图书管理系统,可以用于图书馆。
虽然书籍和作者的数据是相关的,但它们是两个不同的对象,在这些情况下,软件开发人员通常会将每个对象编码到不同的终端,以便向API用户显示他们正在互动的数据类型。
让我们为一个小型库创建一个新的服务器,该服务器将返回两种不同的数据类型. 如果用户访问我们服务器的地址在/books
,他们将收到 JSON 中的书籍列表.如果他们前往/authors
,他们将收到 JSON 中的作者信息列表。
到目前为止,我们一直在向我们收到的每个请求返回相同的响应,让我们快速说明这一点。
重新运行我们的 JSON 响应示例:
1node json.js
在另一个终端中,让我们像以前一样执行一个cURL请求:
1curl http://localhost:8000
你会看到:
1[secondary_label Output]
2{"message": "This is a JSON response"}
现在让我们尝试另一个 curl 命令:
1curl http://localhost:8000/todos
点击进入
后,您将看到相同的结果:
1[secondary_label Output]
2{"message": "This is a JSON response"}
我们没有在我们的requestListener()
函数中构建任何特殊的逻辑来处理 URL 包含/todos
的请求,因此 Node.js 默认情况下会返回相同的 JSON 消息。
由于我们想要构建一个小型库管理服务器,我们现在将根据用户访问的端点分离返回的数据类型。
首先,请使用CTRL+C
离开正在运行的服务器。
现在,在文本编辑器中打开routes.js
:
1nano routes.js
让我们先将我们的 JSON 数据存储在requestListener()
函数之前的变量中:
1[label first-servers/routes.js]
2...
3const books = JSON.stringify([
4 { title: "The Alchemist", author: "Paulo Coelho", year: 1988 },
5 { title: "The Prophet", author: "Kahlil Gibran", year: 1923 }
6]);
7
8const authors = JSON.stringify([
9 { name: "Paulo Coelho", countryOfBirth: "Brazil", yearOfBirth: 1947 },
10 { name: "Kahlil Gibran", countryOfBirth: "Lebanon", yearOfBirth: 1883 }
11]);
12...
书籍
变量是一个包含JSON的字符串,每个书籍都有一个标题或名字,一个作者,以及它出版的年份。
作者
变量是一个包含一系列作者对象的 JSON 字符串,每个作者都有一个名字、出生国和出生年份。
现在我们已经有了回复的数据,让我们开始修改requestListener()
函数以将其返回正确的路径。
首先,我们将确保我们的服务器的每个响应都有正确的内容类型
标题:
1[label first-servers/routes.js]
2...
3const requestListener = function (req, res) {
4 res.setHeader("Content-Type", "application/json");
5}
6...
现在,我们要根据用户访问的 URL 路径返回正确的 JSON。
1[label first-servers/routes.js]
2...
3const requestListener = function (req, res) {
4 res.setHeader("Content-Type", "application/json");
5 switch (req.url) {}
6}
7...
要从请求对象中获取 URL 路径,我们需要访问其url
属性,现在我们可以将案例添加到交换
语句中,以返回相应的 JSON。
JavaScript 的交换
语句提供了一种方式来控制取决于对象或 JavaScript 表达式的值(例如,数学操作的结果)所运行的代码。
让我们继续添加一个案例
,当用户希望获得我们的书籍列表:
1[label first-servers/routes.js]
2...
3const requestListener = function (req, res) {
4 res.setHeader("Content-Type", "application/json");
5 switch (req.url) {
6 case "/books":
7 res.writeHead(200);
8 res.end(books);
9 break
10 }
11}
12...
我们将我们的状态代码设置为200
,表示请求是好的,并返回包含我们书籍列表的JSON。
1[label first-servers/routes.js]
2...
3const requestListener = function (req, res) {
4 res.setHeader("Content-Type", "application/json");
5 switch (req.url) {
6 case "/books":
7 res.writeHead(200);
8 res.end(books);
9 break
10 case "/authors":
11 res.writeHead(200);
12 res.end(authors);
13 break
14 }
15}
16...
和以前一样,状态代码将是200
,因为请求是好的,这次我们返回包含我们作者列表的JSON。
如果用户试图转到任何其他路径,我们希望返回错误. 让我们添加默认案例来做到这一点:
1[label routes.js]
2...
3const requestListener = function (req, res) {
4 res.setHeader("Content-Type", "application/json");
5 switch (req.url) {
6 case "/books":
7 res.writeHead(200);
8 res.end(books);
9 break
10 case "/authors":
11 res.writeHead(200);
12 res.end(authors);
13 break
14 default:
15 res.writeHead(404);
16 res.end(JSON.stringify({error:"Resource not found"}));
17 }
18}
19...
我们在一个交换
声明中使用默认
关键字来捕捉我们以前的案例未捕捉到的所有其他场景,我们将状态代码设置为404
,以表明他们正在寻找的URL没有找到。
让我们测试我们的服务器,看看它是否像我们预期的那样表现。在另一个终端中,让我们先运行一个命令,看看我们是否可以恢复我们的书籍列表:
1curl http://localhost:8000/books
点击Enter
以查看以下输出:
1[secondary_label Output]
2[{"title":"The Alchemist","author":"Paulo Coelho","year":1988},{"title":"The Prophet","author":"Kahlil Gibran","year":1923}]
到目前为止很好. 让我们尝试为 / 作者
做同样的事情. 在终端中输入以下命令:
1curl http://localhost:8000/authors
当命令完成时,您将看到以下输出:
1[secondary_label Output]
2[{"name":"Paulo Coelho","countryOfBirth":"Brazil","yearOfBirth":1947},{"name":"Kahlil Gibran","countryOfBirth":"Lebanon","yearOfBirth":1883}]
最后,让我们尝试一个错误的 URL 来确保 requestListener()
返回错误响应:
1curl http://localhost:8000/notreal
输入该命令将显示此消息:
1[secondary_label Output]
2{"error":"Resource not found"}
您可以使用CTRL+C
退出运行服务器。
我们现在为用户创建了不同的途径,以获取不同的数据,我们还添加了默认响应,如果用户输入我们不支持的 URL,则会返回 HTTP 错误。
结论
在本教程中,您制作了一系列 Node.js HTTP 服务器. 您首先返回了一个基本的文本响应. 然后您继续从我们的服务器返回各种类型的数据: JSON, CSV 和 HTML. 从那里,您可以将文件加载与 HTTP 响应相结合,从服务器返回一个 HTML 页面给用户,并创建一个 API,该 API 使用用户请求的信息来确定应在响应中发送哪些数据。
您现在可以创建能够处理各种请求和响应的网页服务器. 有了这些知识,您可以创建一个服务器,在不同的端点向用户返回许多HTML页面。
要了解 Node.js 中的更多 HTTP 网页服务器,您可以阅读http
模块上的 Node.js 文档。