<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ REST - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ freeCodeCamp 是一个免费学习编程的开发者社区，涵盖 Python、HTML、CSS、React、Vue、BootStrap、JSON 教程等，还有活跃的技术论坛和丰富的社区活动，在你学习编程和找工作时为你提供建议和帮助。 ]]>
        </description>
        <link>https://www.freecodecamp.org/chinese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ REST - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/chinese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 26 May 2026 20:24:25 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/chinese/news/tag/rest/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ 表现层状态转换（REST）是什么？有什么优点？ ]]>
                </title>
                <description>
                    <![CDATA[ 原文：The Benefits of Going RESTful – What is REST and Why You Should Learn About It [https://www.freecodecamp.org/news/benefits-of-rest/]，作者：YiğitKemalErinç [https://www.freecodecamp.org/news/author/erinc/] 在这篇文章中，我们将看看表现层状态转换（REST）原则，了解它们是什么，以及你能从应用它们中得到什么好处。 我相信了解你为什么要学习一些东西是很重要的——包括REST。因此，让我们来看看REST原则带来了什么。 什么是REST? 表现层状态转换（REST）是一种架构风格，由于其简单性和可扩展性，近年来得到了很多人的青睐。 在REST得到普及之前，SOAP是访问资源和通过网络进行通信的事实方式。 你为什么要考虑REST？ 在本节中，我将讨论为什么REST原则很重要，以及为什么值得努力去了解它们。你还将学习如何将它们应用于你的后端项目。 REST很容易理解和实施 EST是为了 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/benefits-of-rest/</link>
                <guid isPermaLink="false">624bc50299ec7406219e570f</guid>
                
                    <category>
                        <![CDATA[ REST ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ luojiyin ]]>
                </dc:creator>
                <pubDate>Tue, 05 Apr 2022 04:30:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2022/04/1_sPLooWMag11pjZnzYXIQCA.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>原文：<a href="https://www.freecodecamp.org/news/benefits-of-rest/">The Benefits of Going RESTful – What is REST and Why You Should Learn About It</a>，作者：<a href="https://www.freecodecamp.org/news/author/erinc/">YiğitKemalErinç</a></p><!--kg-card-begin: markdown--><p>在这篇文章中，我们将看看表现层状态转换（REST）原则，了解它们是什么，以及你能从应用它们中得到什么好处。</p>
<p>我相信了解你为什么要学习一些东西是很重要的——包括REST。因此，让我们来看看REST原则带来了什么。</p>
<h2 id="rest">什么是REST?</h2>
<p>表现层状态转换（REST）是一种架构风格，由于其简单性和可扩展性，近年来得到了很多人的青睐。</p>
<p>在REST得到普及之前，SOAP是访问资源和通过网络进行通信的事实方式。</p>
<h2 id="rest">你为什么要考虑REST？</h2>
<p>在本节中，我将讨论为什么REST原则很重要，以及为什么值得努力去了解它们。你还将学习如何将它们应用于你的后端项目。</p>
<h3 id="rest">REST很容易理解和实施</h3>
<p>EST是为了在HTTP上工作（实际上HTTP受到了REST的影响）。因此，它使用了我们大多数人都知道的HTTP动词，如GET、POST和PUT。</p>
<p>即使你不知道这些动词是干什么的，它们的名字也是不言自明的。另外，客户端和服务器代码的明确分离使得不同的团队很容易在应用程序的不同部分（前端或后端）工作。</p>
<p>由于它很容易理解，也很容易实现，REST原则可以帮助提高你的开发团队的生产力。如果你要发布一个公共API供人们开发应用，它们也很重要。</p>
<p>许多人知道REST和HTTP，所以他们会更容易理解和使用你的API。</p>
<p><img src="https://ucarecdn.com/f9a4640d-ba7f-4f85-82eb-901a56362a9a/" alt="How to Keep Your Developer Team Happy: Lead Dev New York 2019 | Arc Blog" width="600" height="400" loading="lazy"></p>
<h3 id="rest">REST使你的应用程序更具可扩展性</h3>
<p>有2个主要的原因，REST可以帮助使你的应用程序更具可扩展性：</p>
<h4 id="">无状态</h4>
<p>正如我们将在下一节（REST的原则）中看到的，REST的核心原则之一是它在服务器端是无状态的。因此，每个请求的处理都将独立于之前的请求。</p>
<p>在具有服务器端状态或会话的应用程序中，可能为每个登录的用户存储一个会话。这种会话数据很容易变得臃肿，并开始占用服务器上的大量资源。</p>
<p>另一方面，无状态服务器只在处理请求时占用资源（内存），一旦请求被处理完毕，就会释放资源。</p>
<p>由于目前可扩展性的趋势是水平扩展（通常是在云上），存储服务器端的会话也会使你的应用程序难以扩展，因为它产生了一些困难的问题。</p>
<p>例如，假设你有许多服务器，它们在一个负载平衡器后面运行。如果客户在他们的第一个请求中到达了服务器1（服务器1现在拥有客户的会话），而在后来，由于服务器1的负载，客户到达了服务器2，而服务器2并不知道他们之前存储在服务器1上的会话数据，那么会发生什么？当然，这个问题有解决办法，但它使可扩展性更加困难。</p>
<h4 id="">更快的数据交换格式</h4>
<p>RESTful APIs通常使用JSON作为数据交换格式。与XML相比，JSON更紧凑，尺寸更小。它也可以比XML更快地被解析。(<a href="http://ijcsn.org/IJCSN-2014/3-4/JSON-vs-XML-A-Comparative-Performance-Analysis-of-Data-Exchange-Formats.pdf">对比数据来源</a>)</p>
<p>虽然他们大多使用JSON操作，但也要记住，REST APIs仍然能够通过使用 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept">Accept header</a>来响应不同的格式。</p>
<h3 id="rest">使用REST缓存更容易</h3>
<p>缓存是现代网络应用程序可扩展性和性能的一个关键因素。一个完善的缓存机制（具有最佳的命中率）可以大大减少服务器的平均响应时间。</p>
<p>REST的目的是使缓存更容易。由于服务器是无状态的，每个请求都可以单独处理，GET请求通常应该返回相同的响应，而不考虑之前的请求和会话。</p>
<p>这使得GET请求很容易被缓存，浏览器通常也会这样对待它们。我们也可以使用 <strong>Cache-Control</strong> 和 <strong>Expires</strong> 头来使我们的POST请求可以缓存。</p>
<h3 id="rest">REST是灵活的</h3>
<p>我所说的灵活性是指它很容易修改，而且它还能回答许多客户的要求，他们可以要求不同的数据类型（XML、JSON等）。</p>
<p>客户端可以使用<strong>Accept</strong>头来指定类型（正如我前面提到的），REST API可以根据这一点返回不同的响应。</p>
<p>另一个值得一提的机制是 <a href="https://www.wikiwand.com/en/HATEOAS#:~:text=Hypermedia%20as%20the%20Engine%20of,provid%20information%20dynamically%20through%20hypermedia%E3%80%82">HATEOAS</a>。如果你不知道这个词，不要担心，它的基本意思是。在服务器响应中返回某一特定资源的相关URLs。</p>
<p>看一下维基百科上的这个例子。客户端从银行的API中请求带有 <code>account_number</code> 的账户信息，得到这样的响应：</p>
<pre><code class="language-json">
{
    "account": {
        "account_number": 12345,
        "balance": {
            "currency": "usd",
            "value": 100.00
        },
        "links": {
            "deposit": "/accounts/12345/deposit",
            "withdraw": "/accounts/12345/withdraw",
            "transfer": "/accounts/12345/transfer",
            "close": "/accounts/12345/close"
        }
    }
}
</code></pre>
<p>这个服务器利用HATEOAS并返回相应的行动链接。这使得探索API非常容易，同时也通过允许服务器改变端点而使其变得灵活。</p>
<p>可以这样想：如果服务器没有应用HATEOAS，客户就需要对端点进行硬编码，如 "/accounts/:account-id/deposit"。但如果服务器将URL改为 "/accounts/:account-id/depositMoney"，客户端的代码也需要改变。</p>
<p>在HATEOAS链接的帮助下，客户端可以通过解析这个JSON来检查链接，并轻松提出请求。如果端点发生变化，他们将得到新的端点，而不需要改变客户端的代码。</p>
<p>关于这个话题的更多见解，你可以查看 Roy Fielding 的<a href="https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven">这篇文章</a>。</p>
<h2 id="">总结</h2>
<p>在这篇文章中，我试图表达我为什么重视REST，以及为什么我相信你也应该重视它。我希望在读完这篇文章后，你会更清楚应用REST标准的原因。</p>
<p>这篇文章可以作为学习更多相关知识的动力。而且我有个好消息：我计划在不久的将来写关于REST最佳实践和常见错误的文章。</p>
<p>如果你有兴趣，你可以继续关注或订阅我的<a href="http://erinc.io/">博客</a>。你也可以在那里看一下我以前的文章:)</p>
<p>如果你有任何问题或想进一步讨论这个话题，你可以随时联系我。</p>
<p>祝你新年快乐，感谢你阅读本文:)</p>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ REST API 教程：REST 客户端，REST 服务及 API 调用（含代码示例） ]]>
                </title>
                <description>
                    <![CDATA[ 有想过网站的注册/登录功能在后端是怎么实现的吗？你在 YouTube 上搜索“cute kitties”，得到一堆结果，然后观看视频的过程又是怎么回事？ 这个入门教程会带着你一起构建一个 RESTful API，我会解释一些术语，并使用 NodeJS 来编码实现一个服务端程序。 术语解释 REST 是什么？维基百科： > 表现层状态转换（Representational state transfer，REST）  是一种软件架构风格，它定义了一组创建 Web 服务的约束。RESTful Web 服务允许请求系统通过使用统一和预定义的无状态操作集来访问和操作 Web 资源的文本表示。 揭开神秘面纱，看看 REST 究竟是什么意思。REST 基本上就是客户端和服务端通信的一组规则。REST 架构的限制条件：  1. 客户端-服务器架构：网站/应用的用户界面与数据请求/存储应当是分离的，两者可以独立扩展。  2. 无状态：通讯过程中服务端不会保存客户端的上下文信息，意味着每个请求都需要携带必要的数据、不能指望服务器会使用之前的请求中携带的数据。  3. 分层系统：客户端不应该了解 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/rest-api-tutorial-rest-client-rest-service-and-api-calls-explained-with-code-examples/</link>
                <guid isPermaLink="false">5ffbcff339641a0517d538ef</guid>
                
                    <category>
                        <![CDATA[ REST ]]>
                    </category>
                
                    <category>
                        <![CDATA[ API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ 客户端 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Humilitas ]]>
                </dc:creator>
                <pubDate>Mon, 11 Jan 2021 04:16:38 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/01/photo-1558494949-ef010cbdcc31.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>有想过网站的注册/登录功能在后端是怎么实现的吗？你在 YouTube 上搜索“cute kitties”，得到一堆结果，然后观看视频的过程又是怎么回事？</p>
<p>这个入门教程会带着你一起构建一个 RESTful API，我会解释一些术语，并使用 NodeJS 来编码实现一个服务端程序。</p>
<h2 id="">术语解释</h2>
<p>REST 是什么？维基百科：</p>
<blockquote>
<p><strong>表现层状态转换（Representational state transfer，REST）</strong> 是一种软件架构风格，它定义了一组创建 Web 服务的约束。RESTful Web 服务允许请求系统通过使用统一和预定义的无状态操作集来访问和操作 Web 资源的文本表示。</p>
</blockquote>
<p>揭开神秘面纱，看看 REST 究竟是什么意思。REST 基本上就是客户端和服务端通信的一组规则。REST 架构的限制条件：</p>
<ol>
<li><strong>客户端-服务器架构</strong>：网站/应用的用户界面与数据请求/存储应当是分离的，两者可以独立扩展。</li>
<li><strong>无状态</strong>：通讯过程中服务端不会保存客户端的上下文信息，意味着每个请求都需要携带必要的数据、不能指望服务器会使用之前的请求中携带的数据。</li>
<li><strong>分层系统</strong>：客户端不应该了解它是与服务器直接通讯还是与一些中介服务进行通讯，中介服务（代理或负载均衡）为底层服务器的扩展性和安全性提供了保障。</li>
</ol>
<p>理解了 RESTful 服务之后，再了解一下标题中提到的一些术语：</p>
<ol>
<li><strong>REST 客户端</strong>：访问 REST 服务的代码或应用。你现在正在用着它呢！浏览器可以看做是一个不受我们控制的 REST 客户端（我们访问的网站会处理浏览器的请求）。在很长一段时间内，浏览器都是使用内建的 XMLHttpRequest 函数来发起 REST 请求，不过现在它被现代的、基于 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">promise</a> 的 <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">FetchAPI</a> 替代了。其他 REST 客户端还包括：<a href="https://github.com/axios/axios">axios</a>、<a href="https://github.com/visionmedia/superagent">superagent</a>、<a href="https://github.com/sindresorhus/got">got</a> 等代码库，<a href="https://www.postman.com/">Postman</a>（或其在线版本 <a href="https://postwoman.io/">postwoman</a>）等专用应用，以及 <a href="https://curl.haxx.se/">cURL</a> 等命令行工具。</li>
<li><strong>REST 服务</strong>：服务器。有许多流行的库能帮助我们轻松创建 REST 服务，如 NodeJS 环境下的 <a href="https://expressjs.com/">ExpressJS</a> 和 Python 环境下的 <a href="https://www.djangoproject.com/">Django</a>。</li>
<li><strong>REST API</strong>：定义了从服务器存取数据的端点和方法，稍后会详细介绍。其它替代方案包括：GraphQL、JSON-Pure 以及 oData。</li>
</ol>
<h2 id="rest">现在告诉我，REST 是什么？</h2>
<p>广义地说，就是客户端向服务端请求访问指定数据或者在服务端保存数据、服务端响应客户端请求的过程。</p>
<p>从编程角度来说，服务端提供了一个端点（URL）等待接收客户端的请求，客户端连接这个端点并发送数据（记住，REST 是无状态的，请求中携带的数据不会被存储）、服务端返回正确的响应。</p>
<p>文字是枯燥的，我们来看看示例。使用 Postman 来展示请求和响应：</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/image-162.png" alt="image-162" width="600" height="400" loading="lazy"></p>
<p>配置 postman 请求</p>
<p>返回的数据是 JSON（JavaScript Object Notation）格式的，可以直接访问。</p>
<p>这里的 <code>https://official-joke-api.appspot.com/random_joke</code> 被称为 API 端点，服务端会监听指向这个端点的请求。</p>
<h2 id="rest">REST 剖析：</h2>
<p>现在我们知道了客户端可以向服务端发送携带数据的请求、服务端会返回适当的响应，再来深入了解一下如何构造一个请求。</p>
<ol>
<li>
<p><strong>端点（Endpoint）</strong>：前面已经介绍过了，这里再复习一下：它是 REST 服务器监听的 URL 地址。</p>
</li>
<li>
<p><strong>请求方法（Method）</strong>：之前有介绍到，你可以从服务器获取数据或者修改数据，那么服务器怎么知道客户端想要做什么操作呢？REST 为不同的请求类型实现了许多“方法”，以下是最常用的：</p>
<p>-  <strong>GET</strong>：从服务器获取资源。</p>
<p>-  <strong>POST</strong>：在服务器上保存资源。</p>
<p>-  <strong>PATCH</strong> 或 <strong>PUT</strong>：更新服务器上的现有资源。</p>
<p>-  <strong>DELETE</strong>：删除服务器上现有的资源。</p>
</li>
<li>
<p><strong>头部信息（Headers）</strong>：用于客户端和服务端通讯的额外信息（记住，REST 是无状态的）。常见的头部信息如下：</p>
<p><strong>请求头（Request）</strong>：</p>
<p>-  <em>host</em>：客户端的 IP 地址（或请求的源地址）</p>
<p>-  <em>accept-language</em>：客户端接受的语言类型</p>
<p>-  <em>user-agent</em>：客户端的详细信息，如操作系统和浏览器类型</p>
<p><strong>响应头（Response）</strong>：</p>
<p>-  <em>status</em>：请求的状态或 HTTP 状态码</p>
<p>-  <em>content-type</em>：服务器返回的资源的类型</p>
<p>-  <em>set-cookie</em>：服务器设置的 cookies</p>
</li>
<li>
<p><strong>请求数据（Data）</strong>：（也称为请求体或消息）包含了将要发送给服务器的数据</p>
</li>
</ol>
<h2 id="">跳出细节 - 开始编码</h2>
<p>在 Node 环境中编写 REST 服务的代码，我们会实现上面学到的全部内容。在编码过程中会用到 ES6+ 的语法。</p>
<p>要确保你已经安装了 Node.JS，并且 <code>node</code> 和 <code>npm</code> 命令是可用的，我自己使用的版本分别是 Node 12.16.2 和 NPM 6.14.4。</p>
<p>创建一个名为 <code>rest-service-node</code> 的文件夹，并使用 cd 命令进入：</p>
<pre><code class="language-shell">mkdir rest-service-node
cd rest-service-node
</code></pre>
<p>初始化 node 项目：</p>
<pre><code class="language-shell">npm init -y
</code></pre>
<p>参数 <code>-y</code> 表示跳过所有配置项。如果想要手动填写这些配置的话，执行 <code>npm init</code>。</p>
<p>安装一些依赖包，这里使用 ExpressJS 框架来开发 REST 服务。执行以下命令来安装：</p>
<pre><code class="language-shell">npm install --save express body-parser
</code></pre>
<p>这里的 <code>body-parser</code> 是做什么用的？默认情况下，Express 是无法处理 POST 请求传入的 JSON 数据的，<code>body-parser</code> 为 Express 解决了这个问题。</p>
<p>创建 <code>server.js</code> 文件，写入以下代码：</p>
<pre><code class="language-js">const express = require("express");
const bodyParser = require("body-parser");

const app = express();
app.use(bodyParser.json());

app.listen(5000, () =&gt; {
  console.log(`Server is running on port 5000.`);
});
</code></pre>
<p>前两行代码引入了 Express 和 body-parser。</p>
<p>第三行代码初始化了一个 Express 服务器，并把它赋值给一个名为 <code>app</code> 的变量。</p>
<p><code>app.use(bodyParser.json());</code> 初始化了 body-parser 插件。</p>
<p>最后，设置服务器监听 <code>5000</code> 端口的请求。</p>
<h3 id="rest">从 REST 服务器获取数据</h3>
<p>使用 <code>GET</code> 请求来获取服务器的数据，在 <code>app.listen</code> 之前插入以下代码：</p>
<pre><code class="language-js">const sayHi = (req, res) =&gt; {
  res.send("Hi!");
};

app.get("/", sayHi);
</code></pre>
<p>这里创建了一个 <code>sayHi</code> 函数，它接受 <code>req</code> 和 <code>res</code> 两个参数（稍后会解释）、返回字符串“Hi!”作为响应。</p>
<p><code>app.get()</code> 方法接受两个参数：接口路径以及有客户端请求这个接口时执行的回调函数。所以最后一行代码可以理解为：服务器监听”/“路径（可能是主页）的请求，如果监听到这个路径上的请求就执行 <code>sayHi</code> 函数。</p>
<p><code>app.get</code> 还为我们提供了一个包含了客户端发送的所有数据的 <code>request</code> 对象，以及一个包含了所有响应方法的 <code>response</code> 对象。虽然它们是作为函数参数来访问的（随意命名也不影响功能），但是一般命名约定建议将它们命名为 <code>res</code>（表示 <code>response</code>） 和 <code>req</code>（表示 <code>request</code>）。</p>
<p>闲言少叙，启动服务器！执行以下代码：</p>
<pre><code class="language-shell">node server.js
</code></pre>
<p>如果一切顺利的话，应该能在控制台看到这个提示：<em>Server is running on port 5000.</em></p>
<p><em>提示：可以将端口号改为任意合适的值。</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/image-160.png" alt="image-160" width="600" height="400" loading="lazy"></p>
<p>打开浏览器，访问 <code>[http://localhost:5000/][11]</code>，将看到如下内容：</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/image-161.png" alt="image-161" width="600" height="400" loading="lazy"></p>
<p>第一个 <code>GET</code> 请求成功执行了！</p>
<h3 id="rest">向 REST 服务器发送数据</h3>
<p>接下来构建一个 <code>POST</code> 请求，这个请求向服务器传入两个数字、服务器会计算并返回两数之和。在 <code>app.get</code> 之后加入以下代码：</p>
<pre><code class="language-js">app.post("/add", (req, res) =&gt; {
  const { a, b } = req.body;
  res.send(`The sum is: ${a + b}`);
});
</code></pre>
<p>我们以 JSON 格式向服务器发送数据：</p>
<pre><code class="language-json">{
    "a":5,
    "b":10
}
</code></pre>
<p>理解一下代码：</p>
<p>第一行调用了 ExpressJS 的 <code>.post()</code> 方法，使得服务器监听 <code>POST</code> 请求，它接受的参数与 <code>.get()</code> 方法相同。这里指定的接口路径是 <code>/add</code>，这样其他人可以通过你的 IP 地址和端口（<code>[http://your-ip-address:port/add][12]</code>）来访问这个接口，在本地也可以通过 <code>localhost:5000/add</code> 这个地址来访问。这里回调函数是以行内函数的形式来编写的。</p>
<p>第二行使用了 ES6 的对象解构语法来读取对象属性。通过请求发送的数据都被保存在了 <code>req</code> 对象的 <code>body</code> 属性中，实际上也可以用以下代码来读取这两个值：</p>
<pre><code class="language-js">const num1 = req.body.a;
const num2 = req.body.b;
</code></pre>
<p>第三行使用 <code>res</code> 对象的 <code>send()</code> 方法来返回计算结果，这里使用了 ES6 的模板字符串语法。使用 Postman 测试一下：</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/image-163.png" alt="image-163" width="600" height="400" loading="lazy"></p>
<p>我们在请求体中设置 <code>a</code> 的值为 5、<code>b</code> 的值为 10，Postman 会在发送的请求中携带这些数据。服务器接收到这个请求时，会以上面的代码所示的方式解析 <code>req.body</code> 中的数据。返回结果展示在下方。</p>
<p>最终代码：</p>
<pre><code class="language-js">const express = require("express");
const bodyParser = require("body-parser");

const app = express();

app.use(bodyParser.json());

const sayHi = (req, res) =&gt; {
  res.send("Hi!");
};

app.get("/", sayHi);

app.post("/add", (req, res) =&gt; {
  const { a, b } = req.body;
  res.send(`The sum is: ${a + b}`);
});

app.listen(5000, () =&gt; {
  console.log(`Server is running on port 5000.`);
});

</code></pre>
<h2 id="rest">REST 客户端</h2>
<p>我们已经创建了一个服务端程序，那么要如何在网站或者 web 程序中访问它呢？现在 REST 客户端库就派上用场了。</p>
<p>我们会构建一个 web 应用，它包含一个表格，可以在其中填入两个数字，从服务端获得它们的计算结果后会展示在页面上。</p>
<p>首先，修改 <code>server.js</code>：</p>
<pre><code class="language-js">const path = require("path");
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
app.use(bodyParser.json());
app.get("/", (req, res) =&gt; {
  res.sendFile(path.join(__dirname, "index.html"));
});
app.post("/add", (req, res) =&gt; {
  const { a, b } = req.body;
  res.send({
    result: parseInt(a) + parseInt(b)
  });
});

</code></pre>
<p>我们引入了 Node 提供的 <code>path</code> 包，用来跨平台地操作路径。接着改变了”/“路径上的 <code>GET</code> 请求的回调函数，在其中使用了 <code>res</code> 对象提供的 <code>sendFile</code> 方法，这个方法允许我们在响应中返回任意格式的文件。所以，每当用户访问”/“路径的时候，他们会看到 <code>index.html</code> 页面的内容。</p>
<p>最后修改了 <code>app.post</code> 函数，现在它会将 <code>a</code> 和 <code>b</code> 转换为整数，并以 JSON 形式返回两者之和。</p>
<p>创建一个名为 <code>index.html</code> 的 html 页面，并在其中添加一些基本样式：</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8" /&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt;
    &lt;title&gt;REST Client&lt;/title&gt;
  &lt;/head&gt;
  &lt;style&gt;
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    .container {
      height: 100vh;
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
    }
    form {
      display: flex;
      flex-direction: column;
      margin-bottom: 20px;
    }
    label,
    input[type="submit"] {
      margin-top: 20px;
    }
  &lt;/style&gt;
  &lt;body&gt;
    &lt;div class="container"&gt;
      &lt;h1&gt;Simple POST Form&lt;/h1&gt;
      &lt;/h1&gt;
      &lt;form&gt;
        &lt;label&gt;Number 1:&lt;/label&gt;
        &lt;input id="num1" type="number" /&gt;
        &lt;label&gt;Number 2:&lt;/label&gt;
        &lt;input id="num2" type="number" /&gt;
        &lt;input type="submit" value="Add"/&gt;
      &lt;/form&gt;
      &lt;div class="result"&gt;Click Add!&lt;/div&gt;
    &lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>在闭合 body 标签之前插入一段 JavaScript 脚本，这样我们就不必维护一个独立的 <code>.js</code> 文件了。我们监听 document 的 <code>submit</code> 事件并为其指定一个回调函数：</p>
<pre><code class="language-js">&lt;script&gt;
    document.addEventListener("submit", sendData);
&lt;/script&gt;
</code></pre>
<p>首先要避免在点击“Add”按钮时刷新页面，可以使用 <code>preventDefault()</code> 方法来实现，同时要获取两个输入框的值：</p>
<pre><code class="language-js">function sendData(e) {
    e.preventDefault();
    const a = document.querySelector("#num1").value;
    const b = document.querySelector("#num2").value;
}
</code></pre>
<p>使用 <code>a</code> 和 <code>b</code> 的值向服务端发送请求。这里我们使用浏览器内置的 <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a> 来发送请求。</p>
<p>Fetch 接收两个参数：接口地址和 JSON 形式的请求参数对象，返回一个 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise</a>。相关知识超出了本文范围，请自行查阅。</p>
<p>在 <code>sendData()</code> 函数中加入以下代码：</p>
<pre><code class="language-js">fetch("/add", {
        method: "POST",
        headers: {
            Accept: "application/json",
            "Content-Type": "application/json"
        },
        body: JSON.stringify({
            a: parseInt(a),
            b: parseInt(b)
        })
    })
    .then(res =&gt; res.json())
    .then(data =&gt; {
        const {
            result
        } = data;
        document.querySelector(
            ".result"
        ).innerText = `The sum is: ${result}`;
    })
    .catch(err =&gt; console.log(err));
</code></pre>
<p>把接口地址的相对路径作为 <code>fetch</code> 函数的第一个参数传入，接着传入一个参数对象作为第二个参数，其中指定了请求方式为 <code>POST</code>。</p>
<p>参数对象中还包含了 <code>headers</code> 参数，其中指定了请求中发送的数据的格式（<code>content-type</code>）和预期响应的数据格式（<code>accept</code>）。</p>
<p>接着传入了请求体 <code>body</code>。还记得使用 Postman 时以 JSON 格式输入数据吗？这里也是类似的情况。由于 express 将请求体当做字符串来处理，并根据 content-type 来解析，所以我们需要使用 <code>JSON.stringify()</code> 方法来将请求体转换为字符串。我们格外谨慎地把输入值转换为了整数，以确保这个请求不会破坏服务器（因为我们没有做数据类型校验）。</p>
<p>最后，如果 fetch 返回的 promise 状态变为完成（fullfilled），我们就能获取到响应数据并将其转换为 JSON 格式，然后就可以在响应对象中获取计算结果并将结果展示在页面上。</p>
<p>如果这个 promise 的状态变为拒绝（rejected），则会在控制台打印错误信息。</p>
<p><code>index.html</code> 的最终代码如下：</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8" /&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt;
    &lt;title&gt;REST Client&lt;/title&gt;
  &lt;/head&gt;
  &lt;style&gt;
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    .container {
      height: 100vh;
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
    }
    form {
      display: flex;
      flex-direction: column;
      margin-bottom: 20px;
    }
    label,
    input[type="submit"] {
      margin-top: 20px;
    }
  &lt;/style&gt;
  &lt;body&gt;
    &lt;div class="container"&gt;
      &lt;h1&gt;Simple POST Form&lt;/h1&gt;
      &lt;/h1&gt;
      &lt;form&gt;
        &lt;label&gt;Number 1:&lt;/label&gt;
        &lt;input id="num1" type="number" /&gt;
        &lt;label&gt;Number 2:&lt;/label&gt;
        &lt;input id="num2" type="number" /&gt;
        &lt;input type="submit" value="Add"/&gt;
      &lt;/form&gt;
      &lt;div class="result"&gt;Click Add!&lt;/div&gt;
    &lt;/div&gt;
    &lt;script&gt;
      document.addEventListener("submit", sendData);
      function sendData(e) {
        e.preventDefault();
        const a = document.querySelector("#num1").value;
        const b = document.querySelector("#num2").value;

        fetch("/add", {
          method: "POST",
          headers: {
            Accept: "application/json",
            "Content-Type": "application/json"
          },
          body: JSON.stringify({
            a: parseInt(a),
            b: parseInt(b)
          })
        })
          .then(res =&gt; res.json())
          .then(data =&gt; {
            const { result } = data;
            document.querySelector(
              ".result"
            ).innerText = `The sum is: ${result}`;
          })
          .catch(err =&gt; console.log(err));
      }
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>我在 glitch 上部署了一个<a href="https://habitual-serious-boater.glitch.me/">小应用</a>供你测试。</p>
<h2 id="">总结：</h2>
<p>通过本文，我们学习了 REST 架构和 REST 请求的相关知识，我们一起构建了一个简单的能够处理 <code>GET</code> 和 <code>POST</code> 请求的 REST 服务器，还构建了一个 web 应用作为 REST 客户端来计算两数之和。</p>
<p>你可以扩展这个项目来处理更多其它类型的请求，甚至将它扩展成一个完整的<a href="https://www.freecodecamp.org/news/building-a-simple-crud-application-with-express-and-mongodb-63f80f3eb1cd/">后端应用</a>。</p>
<p>希望本文能对你有所帮助。如果有任何疑问，可以随时在 twitter 上联系我。Happy Coding!</p>
<!--kg-card-end: markdown--><p>原文：<a href="https://www.freecodecamp.org/news/rest-api-tutorial-rest-client-rest-service-and-api-calls-explained-with-code-examples/">REST API Tutorial – REST Client, REST Service, and API Calls Explained With Code Examples</a>，作者：<a href="https://www.freecodecamp.org/news/author/boxdox/">Vaibhav Kandwal</a></p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
