<?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[ HTTP - 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[ HTTP - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/chinese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 18 Jun 2026 04:56:18 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/chinese/news/tag/http/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ 学习 HTTP 方法：GET、POST 和 DELETE —— 带有代码示例的手册 ]]>
                </title>
                <description>
                    <![CDATA[ 当你与网站或应用进行交互时，潜藏在那些交互后面的过程非常复杂。这些过程的核心之一就是浏览器或应用是如何与服务器通信的。HTTP 方法定义了需要执行的操作——它可能是获取数据、发送信息或更改现有内容。 每种方法都有特定的用途，以保持网络通信的清晰、安全和有序。 在本文中，我们将分解最常见的 HTTP 方法，并解释它们如何运行以实现顺畅的在线互动。 目录  1.  GET 方法              2.  POST 方法              3.  PUT 方法     ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/learn-http-methods-like-get-post-and-delete-a-handbook-with-code-examples/</link>
                <guid isPermaLink="false">67ee8c16a2b8e3047d17aee1</guid>
                
                    <category>
                        <![CDATA[ HTTP ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tsukistar ]]>
                </dc:creator>
                <pubDate>Thu, 03 Apr 2025 10:19:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2025/04/1743687125353-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/learn-http-methods-like-get-post-and-delete-a-handbook-with-code-examples/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Learn HTTP Methods like GET, POST, and DELETE – a Handbook with Code Examples</a>
      </p><!--kg-card-begin: markdown--><p>当你与网站或应用进行交互时，潜藏在那些交互后面的过程非常复杂。这些过程的核心之一就是浏览器或应用是如何与服务器通信的。HTTP 方法定义了需要执行的操作——它可能是获取数据、发送信息或更改现有内容。</p>
<p>每种方法都有特定的用途，以保持网络通信的清晰、安全和有序。</p>
<p>在本文中，我们将分解最常见的 HTTP 方法，并解释它们如何运行以实现顺畅的在线互动。</p>
<h3 id="">目录</h3>
<ol>
<li>
<p><a href="#heading-get-method">GET 方法</a></p>
</li>
<li>
<p><a href="#heading-post-method">POST 方法</a></p>
</li>
<li>
<p><a href="#heading-put-method">PUT 方法</a></p>
</li>
<li>
<p><a href="#heading-patch-method">PATCH 方法</a></p>
</li>
<li>
<p><a href="#heading-delete-method">DELETE 方法</a></p>
</li>
<li>
<p><a href="#heading-head-method">HEAD 方法</a></p>
</li>
<li>
<p><a href="#heading-options-method">OPTIONS 方法</a></p>
</li>
<li>
<p><a href="#heading-trace-method">TRACE 方法</a></p>
</li>
<li>
<p><a href="#heading-connect-method">CONNECT 方法</a></p>
</li>
<li>
<p><a href="#heading-conclusion">总结</a></p>
</li>
</ol>
<h2 id="get">GET 方法</h2>
<p>GET 方法是最常见的 HTTP 方法之一，用于从服务器请求数据。可以把它看作是索取信息而不做任何改变。</p>
<p>当你访问网页时，浏览器发送一个 GET 请求给服务器，要求页面的内容。然后服务器响应数据（如 HTML、图像或其他文件），浏览器进行显示。</p>
<p>关于 GET 的一个重点是它不会对数据进行任何更改。它只是“读取”或检索信息。例如，当你浏览社交媒体或在线搜索产品时，应用或网站使用 GET 来显示数据而不更改它。</p>
<p>另一个关键点是 GET 请求的参数通过URL传递，这意味着请求的数据会显示在浏览器的地址栏中。例如，如果你在网店搜索产品，搜索词会包含在 URL 中。</p>
<h3 id="get">GET 请求示例</h3>
<p>以下是使用 Fetch API 的 JavaScript 中一个简单的 GET 请求示例：</p>
<pre><code class="language-javascript">fetch('https://api.example.com/products?category=shoes')
  .then(response =&gt; response.json())
  .then(data =&gt; console.log(data))
  .catch(error =&gt; console.error('Error:', error));
</code></pre>
<p>在这个例子中，GET 请求被发送到 URL <a href="https://api.example.com/products"><code>https://api.example.com/products</code></a> ，带有查询参数 <code>category=shoes</code>，请求服务器返回鞋子类别的产品。</p>
<h3 id="get">GET 方法的使用场景</h3>
<p>GET 主要用于获取信息，以下是一些常见的应用场景：</p>
<ol>
<li>
<p><strong>加载网页</strong>：每当你在浏览器中输入 URL 或点击链接时，就是在进行 GET 请求。浏览器向服务器请求网页，服务器返回显示内容。</p>
<ul>
<li>示例：<code>GET /index.html HTTP/1.1</code></li>
</ul>
</li>
<li>
<p><strong>从 API 获取数据</strong>：开发者常使用 API（应用程序接口）从外部服务器获取数据。例如，天气应用使用 GET 请求从天气 API 获取当前温度。</p>
<ul>
<li>示例：</li>
</ul>
<pre><code class="language-javascript">fetch('https://api.weather.com/current?city=Lagos')
   .then(response =&gt; response.json())
   .then(data =&gt; console.log(data));
</code></pre>
</li>
<li>
<p><strong>搜索查询</strong>：当你在 Google 或其他搜索引擎中进行搜索时会发出 GET 请求。你输入的搜索词包含在 URL 中，服务器返回匹配结果的列表。</p>
<ul>
<li>示例：<code>GET /search?q=JavaScript</code></li>
</ul>
</li>
<li>
<p><strong>检索文件</strong>：无论你是下载图片、查看 PDF 或播放视频，GET 都用于从服务器获取这些文件。</p>
<ul>
<li>示例：<code>GET /files/image.jpg</code></li>
</ul>
</li>
</ol>
<h3 id="get">GET 请求的最佳实践</h3>
<p>要有效地使用 GET 请求，遵循一些良好的实践以确保数据处理的顺畅和安全是很重要的：</p>
<ol>
<li>
<p><strong>仅用 GET 来检索数据</strong>：GET 请求用于获取数据，而不是发送如密码或个人数据等敏感信息。因为 GET 请求中的参数包含在 URL 中，任何人都可以看到它们。例如，如果你网站登录时，不应该使用 GET 发送密码，因为它会出现在 URL 中。</p>
<ul>
<li>不该做的示例：</li>
</ul>
<pre><code class="language-javascript">fetch('https://example.com/login?username=john&amp;password=secret');
</code></pre>
</li>
<li>
<p><strong>保持 URL 简洁</strong>：由于 GET 请求的数据包含在 URL 中，过长的 URL 会造成问题。浏览器和服务器对于 GET 请求 URL 的数据量也有限制，所以避免放入太多信息。如果需要发送大量数据，考虑改用 POST 请求。</p>
</li>
<li>
<p><strong>为性能启用缓存</strong>：GET 请求通常会被浏览器缓存，即浏览器可以存储响应并无需再次联系服务器就重复使用。这提高了性能，尤其是对于不经常更改的静态内容，如图像或样式表。为此，确保服务器发送适当的 cache-control 头，以便可频繁请求的数据可以更快加载。</p>
<ul>
<li>设置缓存头的示例：</li>
</ul>
</li>
</ol>
<pre><code>    Cache-Control: max-age=3600
</code></pre>
<ol start="4">
<li>
<p><strong>避免使用 GET 请求执行会修改数据的操作</strong>：由于 GET 是一种“安全”的方法，它仅应用于不会修改数据的操作。如果你想创建、更新或删除数据，应使用像 POST、PUT 或 DELETE 这样的方法。例如，如果你不小心使用 GET 来删除资源，可能会有人通过点击链接或刷新页面来删除它，这样做是不安全的。</p>
<ul>
<li><strong>不要</strong>使用 GET 来进行删除操作的示例：</li>
</ul>
</li>
</ol>
<pre><code>    GET /delete/user/123
</code></pre>
<ol start="5">
<li><strong>谨慎处理敏感数据</strong>：由于 GET 请求是 URL 的一部分，它们可能被记录或者保存在浏览器的历史记录中。避免在 GET 请求中发送敏感信息，如密码、信用卡详细信息或隐私数据。处理此类信息时应始终使用 POST 方法，以确保信息保持隐藏。</li>
</ol>
<h2 id="post">POST 方法</h2>
<p>POST 方法用于向服务器发送数据。与仅用于获取数据的 GET 方法不同，POST 方法可以用来提交服务器可以处理或存储的信息。POST 方法通常用于用户输入数据的表单，如用户名、密码或联系信息。</p>
<p>当发出 POST 请求时，数据通过请求体（而非 URL）发送的。这样 POST 方法就成了发送更大或更敏感的信息（如密码）的理想选择，因为数据是隐藏的，不会出现在浏览器的地址栏中。</p>
<p>例如，当你注册一个网站或在博客上提交评论时，使用 POST 方法将你的信息发送到服务器，后者处理并将其存储在数据库中。</p>
<h3 id="post">POST 请求示例</h3>
<p>以下是使用 Fetch API 将表单数据发送到服务器的 POST 请求示例：</p>
<pre><code class="language-javascript">const formData = {
  username: 'john_doe',
  password: 'mypassword123'
};

fetch('https://example.com/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(formData)
})
.then(response =&gt; response.json())
.then(data =&gt; console.log('Success:', data))
.catch(error =&gt; console.error('Error:', error));
</code></pre>
<p>在这个例子中，POST 请求以 JSON 数据的形式在请求体中发送 <code>username</code> 和 <code>password</code>，这是一种安全地处理像密码这样的敏感信息的方法。</p>
<h3 id="getpost">GET 和 POST 的差异</h3>
<p>虽然 GET 和 POST 都用于与服务器通信，但它们的目的不同，处理数据的方式也不同：</p>
<h4 id="">数据传输：</h4>
<ul>
<li>
<p><strong>GET</strong>：数据包含在 URL 中，使其在地址栏中可见。这限制了可发送的数据量。</p>
</li>
<li>
<p><strong>POST</strong>：数据是在请求体中发送的，允许发送更多的信息。这也使得敏感信息不在 URL 中暴露。</p>
</li>
</ul>
<h4 id="">目的：</h4>
<ul>
<li>
<p><strong>GET</strong>：用于获取数据。不会在服务器上改变或修改任何内容。</p>
</li>
<li>
<p><strong>POST</strong>：用于发送可能会改变或增加服务器资源的数据，比如向数据库添加新用户或提交表单。</p>
</li>
</ul>
<h4 id="">缓存：</h4>
<ul>
<li>
<p><strong>GET</strong>：GET 请求可以缓存。因此浏览器可能会保存响应，从而加快后续请求。</p>
</li>
<li>
<p><strong>POST</strong>：POST 请求不会被缓存，因为它们通常涉及新的或更新的数据，这些数据不应重复使用。</p>
</li>
</ul>
<h4 id="">幂等性：</h4>
<ul>
<li>
<p><strong>GET</strong>：多次发送相同的 GET 请求不会改变结果。每次都会返回相同的数据。</p>
</li>
<li>
<p><strong>POST</strong>：多次发送相同的 POST 请求可能会导致不同的结果。例如，提交表单两次可能会创建重复的条目。</p>
</li>
</ul>
<h3 id="post">POST 的常见使用场景</h3>
<p>POST 是在需要向服务器发送数据时的理想选择，通常用于处理或存储。以下是一些常见的使用案例：</p>
<ol>
<li>
<p><strong>提交表单</strong>：每当你在线填写并提交表单时，如注册新闻简讯或在注册表单中输入你的详细信息，POST 方法用于将该信息发送到服务器。服务器会处理数据，将其存储或根据需要执行其他操作。</p>
<ul>
<li>示例：</li>
</ul>
</li>
</ol>
<pre><code class="language-html">    &lt;form action="https://example.com/register" method="POST"&gt;
      &lt;input type="text" name="username" /&gt;
      &lt;input type="password" name="password" /&gt;
      &lt;button type="submit"&gt;Sign Up&lt;/button&gt;
    &lt;/form&gt;
</code></pre>
<ol start="2">
<li>
<p><strong>用户身份验证</strong>：当你使用用户名和密码登录网站时，通常使用 POST 将你的凭据安全地发送到服务器。服务器检查信息，如果凭据匹配，则授权访问你的账户。</p>
</li>
<li>
<p><strong>上传文件</strong>：POST 也用于上传文件，如图像、文档或视频。由于 POST 方法允许发送大量数据，它非常适合上传需要被处理或存储在服务器上的文件。</p>
<ul>
<li>使用表单上传文件的示例：</li>
</ul>
</li>
</ol>
<pre><code class="language-html">    &lt;form action="https://example.com/upload" method="POST" enctype="multipart/form-data"&gt;
      &lt;input type="file" name="file" /&gt;
      &lt;button type="submit"&gt;Upload File&lt;/button&gt;
    &lt;/form&gt;
</code></pre>
<ol start="4">
<li>
<p><strong>创建新资源</strong>：POST 经常在 API 中用于创建新资源。例如，当你向在线商店添加新产品时，POST 方法会被用来将产品详细信息发送到服务器，后者会将产品添加到商店的数据库中。</p>
<ul>
<li>发送产品数据的示例：</li>
</ul>
</li>
</ol>
<pre><code class="language-javascript">    const product = {
      name: 'New Sneakers',
      price: 59.99,
      category: 'Footwear'
    };
</code></pre>
<ol start="5">
<li>
<p><strong>向 API 发送数据</strong>：当需要发送将被处理或存储的数据时，POST 在 API 中被广泛使用。例如，一个记录你的健身进度的应用可能会使用 POST 将你的锻炼细节发送到服务器，在那里它会被存储和分析。</p>
</li>
<li>
<p><strong>在线购物</strong>：当你进行在线购物时，POST 用于将支付详情发送到服务器进行处理。服务器处理交易并用你的订单信息更新系统。</p>
</li>
</ol>
<h2 id="put">PUT 方法</h2>
<p><strong>PUT</strong> 方法用于更新或替换服务器上的现有资源。它将数据发送到服务器，并指示创建一个新的资源（如果不存在）或替换当前的资源。PUT 的关键思想是你告诉服务器资源应该是什么样的。</p>
<p>例如，想象一个网站上的用户资料。如果你使用 PUT 更新你的资料，服务器将用你提供的新数据替换整个资料。资料的每个部分都会完全匹配你发送的内容，因此如果某些信息缺失，它们将被新数据覆盖。</p>
<h3 id="put">PUT 请求示例</h3>
<p>下面是一个使用 Fetch API 更新用户数据的 PUT 请求示例：</p>
<pre><code class="language-javascript">const updatedProfile = {
  username: 'john_doe_updated',
  email: 'john_updated@example.com',
  age: 30
};

fetch('https://example.com/users/123', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(updatedProfile)
})
.then(response =&gt; response.json())
.then(data =&gt; console.log('Updated:', data))
.catch(error =&gt; console.error('Error:', error));
</code></pre>
<p>在此示例中，PUT 请求使用新数据更新用户资料。资料将被 <code>username</code>、<code>email</code> 和 <code>age</code> 的值替换。如果某些数据缺失，例如 <code>phoneNumber</code>，它将从资料中删除。</p>
<h3 id="put">何时使用 PUT</h3>
<p>PUT 主要用于当你希望使用特定的完整数据更新或替换资源时。以下是一些使用 PUT 的常见情形：</p>
<ol>
<li>
<p><strong>更新资源</strong>：当你需要对现有资源进行更改时，PUT 用于发送整个资源的新版本。例如，更新博客文章、产品详情或用户信息需要使用 PUT 完整替换资源。</p>
<ul>
<li>示例：</li>
</ul>
</li>
</ol>
<pre><code class="language-javascript">    const updatedPost = {
      title: 'New Title for My Blog',
      content: 'Updated blog content here...',
      author: 'John Doe'
    };

    fetch('https://example.com/blog/45', {
      method: 'PUT',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(updatedPost)
    });
</code></pre>
<ol start="2">
<li>
<p><strong>创建资源（如果不存在）</strong>：如果你发送一个 PUT 请求到一个尚无资源的特定 URL，服务器将使用你提供的数据创建一个。这在需要预先完全定义的资源时非常有用。</p>
<ul>
<li>如果产品不存在，创建产品的示例：</li>
</ul>
</li>
</ol>
<pre><code class="language-javascript">    const newProduct = {
      id: 101,
      name: 'New Sneakers',
      price: 59.99,
      category: 'Footwear'
    };

    fetch('https://example.com/products/101', {
      method: 'PUT',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(newProduct)
    });
</code></pre>
<ol start="3">
<li>
<p><strong>与 API 协作</strong>：在与 API 交互时，当你需要更新资源如用户资料、产品详情或任何其他结构化数据时，通常使用 PUT。例如，一个待办事项应用可能允许你使用 PUT 更新现有任务的新信息。</p>
<ul>
<li>更新任务的示例：</li>
</ul>
</li>
</ol>
<pre><code class="language-javascript">    const updatedTask = {
      title: 'Updated Task Title',
      completed: true
    };

    fetch('https://example.com/tasks/67', {
      method: 'PUT',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(updatedTask)
    });
</code></pre>
<h3 id="putvspost">PUT vs. POST：关键区别</h3>
<p>虽然 PUT 和 POST 都可以向服务器发送数据，但它们有不同的目的和行为：</p>
<h4 id="">目的</h4>
<ul>
<li>
<p><strong>PUT</strong>：主要用于更新或替换现有资源。如果资源不存在，PUT 也可以创建它。</p>
</li>
<li>
<p><strong>POST</strong>：主要用于创建新资源或提交需要处理的数据。POST 不替换现有资源，而是添加新的。</p>
</li>
</ul>
<h4 id="">数据处理</h4>
<ul>
<li>
<p><strong>PUT</strong>：用新数据替换整个资源。如果请求中缺少部分资源，该部分将被删除或替换。</p>
</li>
<li>
<p><strong>POST</strong>：添加或更新资源而不替换整个资源。例如，提交表单时，POST 向服务器添加新数据而不删除已有内容。</p>
</li>
</ul>
<h4 id="">幂等性</h4>
<ul>
<li>
<p><strong>PUT</strong>：是幂等的，因此多次发送相同的 PUT 请求将始终产生相同的结果。无论你使用 PUT 更新资源多少次，结果都是一样的。</p>
</li>
<li>
<p><strong>POST</strong>：不是幂等的，因此多次提交相同的 POST 请求可能会创建重复的资源或产生不同的结果。</p>
</li>
<li>
<p><strong>PUT</strong>: 最适用于资源的更新和完全替换。例如，如果您要更新在线商店中的产品详情，PUT 确保您发送的所有细节都被新的替换。</p>
</li>
<li>
<p><strong>POST</strong>: 用于创建新条目或发送需要处理的数据。例如，提交在线订单或填写联系表单时使用 POST。</p>
</li>
</ul>
<h2 id="patch">PATCH 方法</h2>
<p><strong>PATCH</strong> 方法用于对服务器上的资源进行部分更新。与完全替换整个资源的 PUT 方法不同，PATCH 允许您在不再发送完整数据的情况下更新资源的特定部分。这使得 PATCH 非常适合于只需调整某些细节而不影响资源的其他部分的场景。</p>
<p>例如，如果您有一个用户资料，只想更新电话号码，PATCH 使您可以仅发送新的电话号码，而其他部分资料保持不变。这种方式更高效，并减少了意外数据丢失的风险。</p>
<h3 id="patch">使用 PATCH 进行部分更新</h3>
<p>PATCH 旨在对资源进行有针对性的更改。其工作原理如下：</p>
<ul>
<li>
<p><strong>有针对性的更改</strong>：当您使用 PATCH 时，您只需指定要更新的字段。例如，如果用户更新他们的邮箱地址，您仅需发送一个包含新邮箱的 PATCH 请求，服务器上的所有其他信息将保持不变。</p>
</li>
<li>
<p><strong>效率</strong>：PATCH 比 PUT 更高效，因为它允许您仅发送正在更改的数据。对于只需修改一小部分的大型资源而言，这可以减少带宽使用。</p>
</li>
<li>
<p><strong>不覆盖</strong>：与 PUT 不同，PATCH 不会替换整个资源。它只更新请求中提供的字段，保证其他字段不受影响。</p>
</li>
</ul>
<h3 id="patch">PATCH 请求示例</h3>
<p>以下是一个使用 PATCH 方法更新特定字段的基本示例，例如更改用户的邮箱地址：</p>
<pre><code class="language-javascript">const updatedEmail = {
  email: 'new_email@example.com'
};

fetch('https://example.com/users/123', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(updatedEmail)
})
.then(response =&gt; response.json())
.then(data =&gt; console.log('Email updated:', data))
.catch(error =&gt; console.error('Error:', error));
</code></pre>
<p>在这个例子中，只有 <code>email</code> 字段被更新。用户资料的其他部分，比如用户名或地址则保持不变。</p>
<h3 id="patchput">何时使用 PATCH 而非 PUT</h3>
<p>在特定情况下，使用 PATCH 比 PUT 更合适：</p>
<ol>
<li>
<p><strong>更新特定字段</strong>：如果您只需要更新资源的一部分，比如更改用户的邮箱地址、为博客文章添加标签或修改单个属性，使用 PATCH 更好。它允许您仅发送需要更新的字段，使请求更高效。</p>
<ul>
<li>示例：更新用户的电话号码。</li>
</ul>
</li>
</ol>
<pre><code class="language-javascript">    const updatedPhone = { phoneNumber: '123-456-7890' };

    fetch('https://example.com/users/123', {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(updatedPhone)
    });
</code></pre>
<ol start="2">
<li>
<p><strong>避免意外的数据丢失</strong>：使用 PUT 时，若遗漏任何字段，可能导致服务器删除或覆盖这些字段。PATCH 通过仅更新提供的特定字段，避免了此风险，确保没有意外的数据丢失。</p>
<ul>
<li>示例：如果您只想更新用户的用户名，而不想覆盖其他字段（如地址或偏好），PATCH 可以确保仅更新用户名。</li>
</ul>
</li>
<li>
<p><strong>性能考量</strong>：PATCH 对于大型资源更为高效。例如，如果您管理一个拥有大量记录的数据库，并且需要更改其中的一小部分内容，PATCH 会减少发送到服务器的数据量，提高性能并加速过程。</p>
<ul>
<li>示例：更新大型订单的状态而不修改整个订单详情。</li>
</ul>
</li>
</ol>
<pre><code class="language-javascript">    const updatedStatus = { status: 'shipped' };

    fetch('https://example.com/orders/987', {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(updatedStatus)
    });
</code></pre>
<ol start="4">
<li>
<p><strong>频繁更新</strong>：在数据经常变化的应用程序中，PATCH 使得仅更新资源的特定部分更加容易，而不影响整个结构。例如，在电子商务平台中，用户可能会经常更新他们的送货地址或支付方式，PATCH 能够处理这些频繁的变化，而无需重新发送整个用户资料。</p>
<ul>
<li>示例：更新订单的送货地址。</li>
</ul>
</li>
</ol>
<pre><code class="language-javascript">    const updatedAddress = {
      shippingAddress: '123 New Street, New City, Country'
    };

    fetch('https://example.com/orders/987', {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(updatedAddress)
    });
</code></pre>
<h3 id="putpatch">PUT 和 PATCH 的关键区别</h3>
<p>以下是 PATCH 和 PUT 的快速对比，这些对比项可以明确每种方法什么时候使用更合适：</p>
<table>
<thead>
<tr>
<th><strong>特性</strong></th>
<th>PUT</th>
<th>PATCH</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>用途</strong></td>
<td>替换整个资源</td>
<td>部分更新资源</td>
</tr>
<tr>
<td><strong>数据处理</strong></td>
<td>要求发送整个资源</td>
<td>只发送需要更新的字段</td>
</tr>
<tr>
<td><strong>效率</strong></td>
<td>对于大型资源效率较低</td>
<td>对于小型的特定更新，效率更高</td>
</tr>
<tr>
<td><strong>幂等性</strong></td>
<td>幂等性（重复后结果相同）</td>
<td>不一定等效（取决于请求）</td>
</tr>
<tr>
<td><strong>数据丢失风险</strong></td>
<td>如果数据丢失，可以覆盖字段</td>
<td>除非指定，否则不会覆盖现有字段</td>
</tr>
</tbody>
</table>
<p><strong>PATCH</strong> 方法在您希望进行部分更新、避免覆盖其他数据并提高请求效率时特别有用。</p>
<h2 id="delete">DELETE 方法</h2>
<p>DELETE 方法用于从服务器中移除资源。当发出 DELETE 请求时，服务器会删除指定的资源，这意味着该资源将不再可访问或可用。此方法常用于删除用户账号、从在线商店移除产品或清除数据库中过期的数据等任务。</p>
<p>与 GET 或 POST 不同，DELETE 不需要在请求中发送 body——只需提供要删除资源的 URL 就足够了。例如，要删除一个特定的博客文章，可以向该文章的 URL 发送 DELETE 请求，服务器将负责将其删除。</p>
<h3 id="delete">DELETE 的工作原理</h3>
<p>要删除某个资源，通常只需提供要移除资源的 URL。不同于 POST 或 PUT 请求，DELETE 请求通常不需要 body。</p>
<h4 id="">示例</h4>
<p>如果您想删除特定的一篇博客文章，可以向其 URL 发送 DELETE 请求：</p>
<pre><code class="language-javascript">fetch('https://example.com/posts/123', {
  method: 'DELETE'
})
.then(response =&gt; response.json())
.then(data =&gt; console.log('Resource deleted:', data))
.catch(error =&gt; console.error('Error:', error));
</code></pre>
<p>这将告诉服务器移除 ID 为 <code>123</code> 的博客文章。</p>
<h3 id="delete">安全使用 DELETE</h3>
<p>DELETE 请求可能带来显著影响，因此需要谨慎使用以避免意外删除有价值的数据。以下是安全处理 DELETE 请求的一些关键考虑：</p>
<ul>
<li>
<p><strong>永久性操作</strong>：一旦 DELETE 请求被处理，资源通常就消失了。在某些情况下，系统可能实现“软删除”功能，其中资源被隐藏但并未完全移除。然而，大多数情况下使用的是“硬删除”，即完全擦除资源。软删除对恢复很有帮助，允许在需要时恢复数据。</p>
</li>
<li>
<p><strong>认证</strong>：DELETE 请求应仅限于授权用户。执行 DELETE 操作前，服务器应验证用户有权限删除资源。例如，只有用户账号的所有者才能删除账号，而不是其他用户。</p>
</li>
<li>
<p><strong>确认</strong>：许多应用程序在处理 DELETE 操作前会提示用户确认意图。此额外步骤可确保用户不会意外删除重要数据，尤其是诸如账户删除等不可逆的操作。</p>
</li>
</ul>
<h4 id="">确认步骤示例：</h4>
<pre><code class="language-javascript">if (confirm("Are you sure you want to delete this post?")) {
  fetch('https://example.com/posts/123', {
    method: 'DELETE'
  })
  .then(response =&gt; console.log('Post deleted'))
  .catch(error =&gt; console.error('Error:', error));
}
</code></pre>
<ul>
<li><strong>可逆性（软删除）</strong>：对于重要数据，通常使用<strong>软删除</strong>是比较好的，它不会完全移除数据，而是在数据库中标记为已删除。这使得在需要时数据可以恢复。例如，许多电子邮件系统会将已删除的邮件保留在“垃圾箱”文件夹中，直到它们被永久删除。</li>
</ul>
<h3 id="delete">处理 DELETE 请求的最佳实践</h3>
<ol>
<li>
<p><strong>需要认证</strong>：只有经过认证的用户才能执行 DELETE 操作。这能防止未经授权的用户删除他们不拥有的资源。例如，用户只能删除他们自己的数据，而不能删除他人的数据。</p>
<ul>
<li><strong>示例</strong>：在内容管理系统（CMS）中，确保只有文章的作者或管理员才能删除它。</li>
</ul>
</li>
<li>
<p><strong>使用确认步骤</strong>：对于关键操作，确认用户的意图后再继续。这对于无法撤销的操作尤为重要，比如删除账户或永久移除文件。</p>
<ul>
<li><strong>示例</strong>：显示一个提示，如“您确定要删除您的账户吗？此操作无法撤销。”</li>
</ul>
</li>
<li>
<p><strong>记录删除操作</strong>：保留 DELETE 请求的记录，包括谁发起了请求以及何时发生。记录对责任、故障排除和在意外删除时的数据恢复非常重要。</p>
<ul>
<li><strong>示例</strong>：在电商系统中，当产品从目录中移除时，记录发起请求的用户及删除时间等详细信息。</li>
</ul>
</li>
<li>
<p><strong>对关键数据使用软删除</strong>：为可能需要恢复的数据实现软删除机制。这在诸如用户账户等场景中特别有用，因为用户可能在删除后希望恢复他们的数据。</p>
<ul>
<li><strong>示例</strong>：当用户“删除”他们的账户时，将其标记为不活跃或隐藏，而不是完全擦除，允许用户在后续恢复。</li>
</ul>
</li>
<li>
<p><strong>优雅地处理错误</strong>：如果 DELETE 请求失败，服务器应返回适当的错误信息。例如，如果资源不存在或用户无权删除它，服务器应响应“资源未找到”或“未授权操作”等信息。</p>
<ul>
<li><strong>示例</strong>：对不存在用户的 DELETE 请求可能返回 <code>404 Not Found</code> 响应。</li>
</ul>
</li>
<li>
<p><strong>仔细检查 URL 目标</strong>：在发送 DELETE 请求之前，确保 URL 指向正确的资源。错误地指向错误的资源可能导致意外的数据丢失。</p>
<ul>
<li><strong>示例</strong>：如果您正在管理一个待办事项列表并想删除单个任务，确保 URL 特别指向该任务而不是整个列表。</li>
</ul>
</li>
<li>
<p><strong>将结果告知用户</strong>：在成功的 DELETE 请求之后，通知用户资源已被删除。可以通过消息或通知确认操作。</p>
<ul>
<li><strong>示例</strong>：在产品或文章从系统中移除后，显示“项目成功删除”之类的消息。</li>
</ul>
</li>
</ol>
<p>通常，一个成功的 DELETE 请求会返回以下状态代码之一：</p>
<ul>
<li>
<p><strong>200 OK</strong>: 表示删除成功，并包含响应主体（例如，确认删除的消息）。</p>
</li>
<li>
<p><strong>204 No Content</strong>: 请求成功，但响应主体中没有返回内容。这在资源删除后非常常见，因为没有内容需要返回。</p>
</li>
<li>
<p><strong>404 Not Found</strong>: 表示要删除的资源不存在。</p>
</li>
</ul>
<h3 id="delete">DELETE 请求响应示例</h3>
<p>如果 DELETE 请求成功且资源已移除，服务器可能会返回一个 <code>204 No Content</code> 状态：</p>
<pre><code class="language-http">HTTP/1.1 204 No Content
</code></pre>
<p>这个响应告诉客户端资源已成功删除，但不会返回任何额外数据。</p>
<h2 id="head">HEAD 方法</h2>
<p>HEAD 方法与 GET 方法类似，但有一个关键区别：它仅检索资源的头信息，而不是实际内容。</p>
<p>当你发送一个 HEAD 请求时，服务器会回应与 GET 请求相同的头信息，但不发送资源主体（如文本、图片或文件）。这使得 HEAD 很适合在不下载整个内容的情况下检查资源的信息，例如其大小或最后修改日期。</p>
<p>例如，如果你正在管理一个大文件并想在下载前检查其大小，可以使用 HEAD 请求从服务器获取此信息，而无需实际获取文件。</p>
<h3 id="headget">HEAD 与 GET 的比较</h3>
<ul>
<li>
<p><strong>相同的头信息，无内容</strong>: HEAD 请求提供与 GET 请求相同的头信息，如 <code>Content-Type</code>、<code>Content-Length</code>、<code>Last-Modified</code> 等。然而，响应不包含主体——仅包含元数据。</p>
</li>
<li>
<p><strong>请求更快</strong>: 由于不包含主体，HEAD 请求比 GET 请求更快并且消耗的带宽更少。这在你只对资源的细节而非内容感兴趣时特别有用。</p>
</li>
</ul>
<h3 id="head">HEAD 的使用场景</h3>
<ol>
<li>
<p><strong>检查资源可用性</strong>: 你可以使用 HEAD 请求检查资源（如网页或文件）是否存在而不获取内容。例如，如果 URL 返回状态代码为 <code>200 OK</code>，你就知道资源存在。<code>404 Not Found</code> 状态代码则表示它不可用。</p>
</li>
<li>
<p><strong>测试链接</strong>: 如果你管理的网站有大量外部链接，可以用 HEAD 请求测试这些链接是否仍然有效，而无需加载整个页面。如果 HEAD 请求返回错误代码，你就知道链接已断开。</p>
</li>
<li>
<p><strong>获取文件元数据</strong>: 如果你在处理大文件，可能需要在下载前检查它们的大小。HEAD 请求允许你收集元数据，如文件大小 (<code>Content-Length</code>) 和类型 (<code>Content-Type</code>)，而不提取整个文件。</p>
</li>
<li>
<p><strong>优化缓存</strong>: 浏览器和应用程序可以使用 HEAD 请求检查资源自缓存以来是否已更新。服务器返回如 <code>Last-Modified</code> 或 <code>ETag</code> 这类头信息，如果这些值未改变，则可以使用缓存版本，从而节省带宽和时间。</p>
</li>
<li>
<p><strong>API 效率</strong>: 当客户端需要验证数据是否存在而不下载整个响应时，HEAD 请求在 API 中很有用。例如，请求可以检查数据库中是否存在记录而无需获取完整细节。</p>
</li>
<li>
<p><strong>服务器健康监控</strong>: HEAD 请求可以用来测量服务器性能。通过测试响应速度而不下载内容，开发者可以监控服务器响应时间、检查问题或确定服务器是否正常运行。</p>
</li>
</ol>
<h3 id="head">使用 HEAD 的最佳实践</h3>
<ul>
<li>
<p><strong>高效测试</strong>: HEAD 非常适合验证资源或测试 API 端点，而不下载不必要的数据。</p>
</li>
<li>
<p><strong>缓存验证</strong>: HEAD 请求有助于缓存验证，确保资源是最新的，而不消耗带宽。</p>
</li>
<li>
<p><strong>无副作用</strong>: 像 GET 一样，HEAD 应该是安全且幂等的，即不应改变资源的状态。它纯粹用于检索信息。</p>
</li>
</ul>
<h2 id="options">OPTIONS 方法</h2>
<p>OPTIONS 方法用于查明对特定资源允许哪些操作。它允许客户端（如浏览器或 API）向服务器询问，“我可以对这个资源执行什么操作？” 服务器则会列出它对该资源支持的 HTTP 方法，如 GET、POST、PUT、DELETE 等。</p>
<p>OPTIONS 不会对资源本身执行任何操作。相反，它提供有关客户端可以执行什么操作的信息。这在你想检查允许哪些操作而不实际提出改变或检索数据的请求时很有用。</p>
<p>例如，如果你正在使用 API 并想查看它是否在特定端点支持 DELETE 方法，可以发送 OPTIONS 请求以获取该信息，而不影响资源。</p>
<h3 id="http">检索目标资源支持HTTP请求的方法</h3>
<ol>
<li>
<p><strong>发送 OPTIONS 请求</strong>：客户端向服务器发送 OPTIONS 请求，通常针对特定 URL。该请求用作关于允许对该端点上的资源执行什么操作的查询。</p>
</li>
<li>
<p><strong>服务器的响应</strong>：服务器通过 <code>Allow</code> 响应头返回该资源支持的 HTTP 方法。例如，可能返回 <code>Allow: GET, POST, DELETE</code>，表示可以使用这些方法。</p>
</li>
<li>
<p><strong>测试方法</strong>: 如果不确定服务器是否支持特定方法（如 PATCH 或 DELETE），可以先发送 OPTIONS 请求进行检查。这可以避免尝试服务器不支持的方法，从而避免错误。</p>
</li>
</ol>
<pre><code class="language-http">OPTIONS /api/resource HTTP/1.1
Host: example.com
</code></pre>
<p>服务器响应：</p>
<pre><code class="language-http">HTTP/1.1 200 OK
Allow: GET, POST, DELETE
</code></pre>
<h3 id="optionscors">OPTIONS 方法在跨域资源共享（CORS）中的使用</h3>
<p>OPTIONS 方法最常见的用途之一是在处理**跨域资源共享（CORS）**时。CORS 是一种安全特性，保证一个域名上的资源不会被另一个域名的网页不当访问。</p>
<h4 id="cors">CORS 和预检请求</h4>
<p>当浏览器需要进行跨域请求（例如，从<a href="http://domainA.com"><code>domainA.com</code></a>请求到<a href="http://api.domainB.com"><code>api.domainB.com</code></a>），浏览器首先会向目标服务器发送一个被称为<strong>预检请求</strong>的<strong>OPTIONS 请求</strong>。预检请求用于检查实际请求是否符合服务器的 CORS 策略。</p>
<ol>
<li>
<p><strong>预检请求</strong>：浏览器在实际请求（如 POST 或 PUT）前发送一个 OPTIONS 请求。该请求询问服务器允许哪些方法、哪些域名可以访问资源，以及是否允许特定的头信息或凭据。</p>
</li>
<li>
<p><strong>服务器响应</strong>：服务器用 CORS 头信息回应，例如 <code>Access-Control-Allow-Methods</code>、<code>Access-Control-Allow-Origin</code> 和 <code>Access-Control-Allow-Headers</code>。这些信息告知浏览器该请求是否可以继续、允许哪些方法或域名。</p>
<p>示例响应：</p>
<pre><code class="language-http">HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://domainA.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type
</code></pre>
</li>
<li>
<p><strong>确保安全性</strong>：CORS 和预检 OPTIONS 请求确保只有在服务器许可的情况下才允许跨域请求。如果没有此安全步骤，网站可能会对其他域名进行未经授权的请求。</p>
</li>
<li>
<p><strong>处理复杂请求</strong>：如果请求包含自定义头信息、使用非简单 HTTP 方法（如 GET 或 POST）或发送诸如 cookies 的凭据，浏览器会自动发送 OPTIONS 预检请求。如果服务器拒绝请求（即返回头信息不允许该操作），浏览器会拦截请求。</p>
</li>
</ol>
<h4 id="">简化的工作流程</h4>
<ul>
<li>
<p><strong>浏览器</strong>： "我可以向[<code>api.domainB.com</code>]请求吗？"</p>
</li>
<li>
<p><strong>服务器</strong>： "可以，你可以使用 <code>GET</code> 和 <code>POST</code>，但只能从[<code>domainA.com</code>]并且使用这些头信息。"</p>
</li>
<li>
<p><strong>浏览器</strong>： 如果响应允许，则继续实际请求。</p>
</li>
</ul>
<h3 id="options">OPTIONS 方法的使用场景</h3>
<ul>
<li>
<p><strong>发现可用方法</strong>：对于开发者来说有用，可以在进行操作之前检查一个资源支持哪些 HTTP 方法。</p>
</li>
<li>
<p><strong>CORS 预检</strong>：在网络安全中至关重要，确保跨域请求是经过适当授权的。</p>
</li>
<li>
<p><strong>提高 API 效率</strong>：API 可以通过 OPTIONS 公开一个资源支持的方法，使客户端更容易理解可以执行哪些操作。</p>
</li>
</ul>
<p>因此，OPTIONS 方法在管理请求权限和提高安全性方面对网络应用程序是必不可少的，特别是在跨域场景中。</p>
<h2 id="trace">TRACE 方法</h2>
<p>TRACE 方法用于调试网络应用程序和测试请求如何通过网络。当你发送一个 TRACE 请求时，会触发一个回环测试，服务器将原样返回它接收到的请求。这有助于开发者查看请求在通过不同系统（如防火墙或代理）到达服务器前是否被修改。</p>
<p>简单来说，TRACE 允许你追踪请求从客户端（如浏览器或 API 工具）到服务器再返回的路径。这种方法对于识别请求传输过程中的问题很有用。</p>
<h3 id="">理解回环测试</h3>
<p>回环测试指的是通过 TRACE 查看请求在跨网络时如何处理，以检查原始请求是否保持完整。具体如下：</p>
<ol>
<li>
<p><strong>发送 TRACE 请求</strong>：你向服务器发送一个 TRACE 请求。这个请求通常较小，包含基本信息如方法、URL 和头信息。它不像 POST 或 PUT 方法那样携带额外数据或负载。</p>
</li>
<li>
<p><strong>服务器响应</strong>：服务器不是以资源作为响应，而是逐字返回它接收到的请求。这包括 HTTP 方法、URL、头信息和原始请求中的其他内容。服务器不修改或处理请求，只是原样返回。</p>
</li>
<li>
<p><strong>追踪路径</strong>：当 TRACE 响应返回时，你可以看到请求经过的完整路径，包括请求头信息或内容中的任何变化。对以下问题的诊断特别有用：</p>
<ul>
<li>
<p><strong>代理服务器</strong>：如果你的请求在到达目的地之前经过一个或多个代理服务器，TRACE 可以显示这些代理是否更改了请求头信息或内容。</p>
</li>
<li>
<p><strong>网络防火墙</strong>：某些网络防火墙可能在请求经过时添加或修改头信息。TRACE 可以揭示这些修改。</p>
</li>
<li>
<p><strong>错误跟踪</strong>：如果请求未按预期运行，TRACE 可以帮助追踪传输过程中出现问题的地方。</p>
</li>
</ul>
</li>
<li>
<p><strong>有效调试</strong>：TRACE 在调试网络应用程序或 API 特别有帮助。如果你的应用程序因路由、代理或服务器配置引发错误，TRACE 让你看到未修改的请求，从而更容易定位问题。</p>
</li>
</ol>
<h3 id="trace">TRACE 的安全问题</h3>
<p>虽然 TRACE 在调试中很有用，但通常被视为安全风险，并且由于多个原因在大多数服务器上经常被禁用：</p>
<ol>
<li>
<p><strong>跨站脚本攻击 (XSS)</strong>：TRACE 方法可能会暴露请求头中的敏感信息，如 Cookie 或认证令牌。恶意行为者可能利用 TRACE 来捕获这些详细信息，导致安全漏洞，特别是在存在跨站脚本攻击 (XSS) 等漏洞时。这使 TRACE 成为攻击者试图窃取用户数据的潜在目标。</p>
</li>
<li>
<p><strong>请求修改暴露</strong>：由于 TRACE 显示了对请求所做的所有修改，它还可以揭示内部代理和防火墙如何处理请求。这可能让攻击者深入了解网络内部运作，为他们策划进一步攻击提供便利。</p>
</li>
<li>
<p><strong>出于安全目的禁用 TRACE</strong>：基于这些原因，TRACE 通常在大多数网络服务器上被禁用以防滥用。在许多现代 Web 应用程序中，存在更为安全的方法用于调试请求和追踪网络路径，因此在日常使用中 TRACE 很少必要。</p>
</li>
<li>
<p><strong>更安全的替代方案</strong>：开发人员可以使用现代 Web 框架和 API 内置的更安全的诊断工具和日志功能。这些替代方案能提供类似的见解而不会带来 TRACE 相关的安全风险。</p>
</li>
</ol>
<h2 id="connect">CONNECT 方法</h2>
<p>CONNECT 方法主要用于通过中介（通常是代理服务器）在客户端和服务器之间建立隧道。当客户端发送 CONNECT 请求时，服务器创建一个隧道，允许加密数据在客户端和目标服务器之间流动。这种方法对于保障连接安全至关重要，特别是当涉及 HTTPS 时。</p>
<p>CONNECT 本身并不处理任何实际数据。它的作用是建立一个安全通信路径，允许加密信息通过代理而不被修改或检查。</p>
<h3 id="connect">CONNECT 的工作原理</h3>
<ol>
<li>
<p><strong>发送 CONNECT 请求</strong>：客户端（如网络浏览器）向代理服务器发送 CONNECT 请求。该请求包含目标服务器的主机名和端口，通常是标准的 HTTPS 端口 (443)。例如，当访问 <a href="https://example.com"><code>https://example.com</code></a> 时，浏览器向代理服务器发送 CONNECT 请求，请求其连接到该域的端口 443。</p>
</li>
<li>
<p><strong>建立隧道</strong>：代理服务器在收到 CONNECT 请求后，建立一条到目标服务器的隧道。该隧道允许加密通信无干扰地通过。代理仅在客户端和目标之间转发流量，充当中继的角色。</p>
</li>
<li>
<p><strong>加密通信</strong>：隧道建立后，客户端和目标服务器可以使用安全加密协议（如 TLS，用于 HTTPS）直接通信。由于数据在客户端和服务器之间是加密的，代理无法解密或修改它。</p>
</li>
<li>
<p><strong>安全数据传输</strong>：通过 CONNECT 方法，敏感数据（如登录凭证、个人信息或金融交易）可以在客户端和服务器之间安全传输，即使是通过代理。加密隧道确保数据保持机密和完整。</p>
</li>
</ol>
<h3 id="connect">CONNECT 请求和响应示例</h3>
<ul>
<li>
<p><strong>CONNECT 请求</strong>：</p>
<pre><code class="language-http">  CONNECT example.com:443 HTTP/1.1
  Host: example.com
</code></pre>
</li>
<li>
<p><strong>代理响应</strong>（若隧道成功建立）：</p>
<pre><code class="language-http">  HTTP/1.1 200 Connection Established
</code></pre>
</li>
</ul>
<h3 id="connect">CONNECT 隧道</h3>
<p>在此环境中，<strong>隧道</strong>一词指的是通过代理在客户端和目标服务器之间创建直接、安全的链接。代理作为中间人存在，但不会干涉或访问通过隧道传输的加密数据。</p>
<h4 id="">隧道过程的步骤：</h4>
<ul>
<li>
<p><strong>发送 CONNECT 请求</strong>：客户端向代理发送 CONNECT 请求，指定目标服务器和端口（例如，HTTPS 的 443 端口）。</p>
</li>
<li>
<p><strong>代理设置隧道</strong>：代理服务器在客户端和目标服务器之间建立安全隧道，在两个端点之间转发流量。</p>
</li>
<li>
<p><strong>开始加密通信</strong>：客户端和目标服务器通过加密隧道直接通信，使用 HTTPS 或其他加密协议。代理转发加密流量但无法访问或修改。</p>
</li>
</ul>
<h3 id="connect">CONNECT 方法的典型使用案例</h3>
<ol>
<li>
<p><strong>通过代理的 HTTPS</strong>：CONNECT 方法最常见的用途之一是启用<strong>通过代理的 HTTPS 流量</strong>。在许多公司或网络环境中，互联网流量必须通过代理服务器。对于使用 HTTPS 的安全网站，CONNECT 方法允许代理服务器建立隧道，在不检查数据的情况下将加密流量从客户端转发到目标服务器。</p>
<ul>
<li><strong>示例</strong>：当您从公司网络访问一个安全的银行网站时，您的浏览器可能需要通过公司代理。CONNECT 方法用于在您的浏览器和银行网站之间建立加密隧道，确保敏感数据（如登录凭证）安全地通过代理。</li>
</ul>
</li>
<li>
<p><strong>VPN 和安全通道</strong>：**VPN（虚拟专用网络）**服务也依赖类似的隧道技术来安全地加密和路由互联网流量。一些 VPN 服务使用 CONNECT 创建安全隧道，确保用户与互联网之间传输的数据加密且不被窃听。</p>
</li>
<li>
<p><strong>访问被封锁的内容</strong>：在某些网站被封锁的环境中（例如，学校或办公室），CONNECT 有时可以用于通过代理建立隧道来绕过限制。虽然这种做法可能违反网络政策，但它说明了 CONNECT 如何用于建立安全、不受监控的访问。</p>
</li>
<li>
<p><strong>自定义代理</strong>：开发人员可能会设置<strong>自定义代理</strong>来为应用程序路由流量以提高性能或安全性。在这种情况下，CONNECT 允许 HTTPS 或其他安全流量通过代理传输，同时保持隐私和安全，因为代理服务器无法访问隧道内的加密数据。</p>
</li>
</ol>
<p>虽然 CONNECT 对于安全通信是必不可少的，但它也带来了一些安全挑战：</p>
<ul>
<li>
<p><strong>绕过内容过滤器</strong>：由于 CONNECT 创建了代理无法检查的加密隧道，它可以被用来绕过内容过滤系统。这使用户能够访问受限的网站或服务，可能违反组织政策。</p>
</li>
<li>
<p><strong>隧道传输恶意流量</strong>：恶意行为者可以利用 CONNECT 通过代理隧道传输有害或未经授权的流量。由于流量是加密的，防火墙和安全系统可能无法检测到恶意活动。</p>
</li>
<li>
<p><strong>缓解措施</strong>：许多组织通过密切监控和限制 CONNECT 方法的使用来解决这些风险。一些代理执行 <strong>SSL 截取</strong> 来解密和检查 HTTPS 流量，尽管这会引发隐私问题并可能影响用户安全。</p>
</li>
</ul>
<h2 id="">结论</h2>
<p>HTTP 方法对于实现 web 应用程序和服务器之间的通信至关重要。从 GET 到 CONNECT，每个方法都为特定任务设计，如发送数据、检索信息、更新资源或建立安全连接。为任务选择正确的方法可以提高应用程序的效率和安全性。</p>
<p>GET 适合检索数据，POST 和 PUT 帮助创建和更新，PATCH 处理部分更新，而 DELETE 用于移除资源。HEAD 检查响应头而不检索内容，OPTIONS 显示支持的方法，TRACE 和 CONNECT 有助于调试和安全通信。</p>
<p>使用适当的 HTTP 方法确保您的应用程序高效、安全地运行，为用户提供流畅的体验。</p>
<p>如果您有任何问题或建议，请随时在 <a href="https://ng.linkedin.com/in/joan-ayebola">LinkedIn</a> 上联系。如果您喜欢这篇内容，请考虑 <a href="https://www.buymeacoffee.com/joanayebola">buy me a coffee</a> 来支持我创作更多对开发者友好的内容。</p>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ HTTP Error 403 Forbidden 是什么意思以及如何解决它 ]]>
                </title>
                <description>
                    <![CDATA[ 上网时收到任何错误代码都可能是一种令人沮丧的经历。虽然我们已经习惯了 404 Not Found 的页面，甚至在我们访问不到 [http://www.limpfish.com/404]的时候经常有可爱 [https://toggl.com/404/]的占位符页面来令人开心 [https://weemss.com/page-not-found/]，但更令人费解的错误之一是 403: Forbidden response。 它是什么意思？ 简单地说：服务器已经确定你不能访问你所请求的东西。 根据 RFC 7231 [https://tools.ietf.org/html/rfc7231#section-6.5.3]， > 403（禁止）状态代码表明服务器理解该请求，但拒绝授权......如果请求中提供了认证凭证，服务器认为它们不足以授予访问权。 403 响应属于 HTTP 响应的 4xx 范围：客户端错误。这意味着你或你的浏览器做错了什么。 如果你遇到这种情况，通常意味着你已经在服务器上验证了自己的身份，也就是说，你已经登录了，但你所请求的资源需要有更高权限的人。 最常见的情况是 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/http-error-403-forbidden-what-it-means-and-how-to-fix-it/</link>
                <guid isPermaLink="false">6377539b7cdd940712f7c94d</guid>
                
                    <category>
                        <![CDATA[ HTTP ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chengjun.L ]]>
                </dc:creator>
                <pubDate>Mon, 14 Nov 2022 08:19:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2022/11/5f9c9eb4740569d1a4ca3e9f.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/http-error-403-forbidden-what-it-means-and-how-to-fix-it/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">HTTP Error 403 Forbidden: What It Means and How to Fix It</a>
      </p><p>上网时收到任何错误代码都可能是一种令人沮丧的经历。虽然我们已经习惯了 404 Not Found 的页面，甚至在我们<a href="http://www.limpfish.com/404">访问不到</a>的时候经常有<a href="https://toggl.com/404/">可爱</a>的占位符页面来令人<a href="https://weemss.com/page-not-found/">开心</a>，但更令人费解的错误之一是 403: Forbidden response。</p><h3 id="-">它是什么意思？</h3><p>简单地说：服务器已经确定你不能访问你所请求的东西。</p><p>根据 <a href="https://tools.ietf.org/html/rfc7231#section-6.5.3">RFC 7231</a>，</p><blockquote>403（禁止）状态代码表明服务器理解该请求，但拒绝授权......如果请求中提供了认证凭证，服务器认为它们不足以授予访问权。</blockquote><p>403 响应属于 HTTP 响应的 4xx 范围：客户端错误。这意味着你或你的浏览器做错了什么。</p><p>如果你遇到这种情况，通常意味着你已经在服务器上验证了自己的身份，也就是说，你已经登录了，但你所请求的资源需要有更高权限的人。</p><p>最常见的情况是，你可能是以标准用户身份登录的，但你正试图访问一个管理员页面。</p><h2 id="--1">你如何解决这个问题？</h2><p>作为一个不能访问服务器的用户，你实际上只有几个选择：</p><h3 id="--2">用一个更合适的账户认证</h3><p>同样，根据 <a href="https://tools.ietf.org/html/rfc7231#section-6.5.3">RFC 7231</a> 的规定：</p><blockquote>如果在请求中提供了认证凭证，服务器认为它们不足以授予访问权，客户端不应该自动用相同的凭证重复请求，客户端可以用新的或不同的凭证重复请求。</blockquote><p>这是唯一能让你立即纠正问题的方法。</p><p>如果你在一个网站上有多个账户，你试图做一些你通常可以做的事情，但这次被禁止做，这是你应该尝试的选项。用你的其他账户登录。</p><p>你可能会发现，这个选项也需要清除你的缓存或 cookies，以防以另一个用户身份登录时不能充分刷新之前的认证令牌。但这通常是不必要的。</p><p>作为一个无奈之举，你也可以尝试禁用可能干扰你使用该网站的浏览器扩展。然而，这是不可能的，因为 403 意味着你已被认证，但没有被授权。</p><h3 id="-403">通知网站所有者返回的是 403</h3><p>如果你完全预计你应该能够访问有关资源，但你仍然看到这个错误，明智的做法是让网站背后的团队知道——这可能是他们的一个错误。</p><p>再来看看 <a href="https://tools.ietf.org/html/rfc7231#section-6.5.3">RFC 7231</a> 的内容：</p><blockquote>然而，一个请求可能因为与证书无关的原因而被禁止。</blockquote><p>无意中发生这种情况的一个常见原因是，服务器对特定的 IP 地址或地理区域使用了允许或拒绝名单。</p><p>他们可能有很好的理由阻止你在他们严格定义的参数之外的访问，但也可能只是一个疏忽。</p><h3 id="--3">放弃</h3><p>也许你只是不应该能够访问该资源。这种情况时有发生。互联网很大，有一些区域不允许你个人访问，这是合理的。</p><p>你可以在思考为什么你的原始请求被<a href="https://http.cat/403">禁止</a>时转而访问 <a href="https://http.cat/">http.cat</a>。</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ HTTP 和 HTTPS 的区别是什么 ]]>
                </title>
                <description>
                    <![CDATA[ 我们每天都和HTTP和HTTPS打交道，但是很多人都不知道这两者之间的区别是什么。 大多数计算机用户看到浏览器告知他们这个应用不安全，很有可能有黑客想要获取他们重要的信息的时候，用户可能跑得比博尔特还要快。 但这个安全风险是可以避免的，这就是为什么HTTPS引入并取代HTTP。今天我们就来讨论这个话题。 :) 我们将讨论：  1.  什么是HTTP  2.  HTTP如何工作  3.  HTTP的功能  4.  如何知道一个网站不安全  5.  所有的HTTP网站都不安全吗  6.  什么是HTTPS  7.  HTTPS如何工作  8.  HTTPS的功能  9.  加密的工作原理  10. 如何知道一个网站是安全的  11. SSL证书是什么  12. SSL是如何工作的 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/http-vs-https/</link>
                <guid isPermaLink="false">6303493460480505ded7ade3</guid>
                
                    <category>
                        <![CDATA[ HTTPS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTTP ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ PapayaHUANG ]]>
                </dc:creator>
                <pubDate>Mon, 22 Aug 2022 03:20:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2022/08/HTTP-VS-HTTPS.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/http-vs-https/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">HTTP vs HTTPS – What's the Difference?</a>
      </p><!--kg-card-begin: markdown--><p>我们每天都和HTTP和HTTPS打交道，但是很多人都不知道这两者之间的区别是什么。</p>
<p>大多数计算机用户看到浏览器告知他们这个应用不安全，很有可能有黑客想要获取他们重要的信息的时候，用户可能跑得比博尔特还要快。</p>
<p>但这个安全风险是可以避免的，这就是为什么HTTPS引入并取代HTTP。今天我们就来讨论这个话题。 :)</p>
<h2 id="">我们将讨论：</h2>
<ol>
<li>什么是HTTP</li>
<li>HTTP如何工作</li>
<li>HTTP的功能</li>
<li>如何知道一个网站不安全</li>
<li>所有的HTTP网站都不安全吗</li>
<li>什么是HTTPS</li>
<li>HTTPS如何工作</li>
<li>HTTPS的功能</li>
<li>加密的工作原理</li>
<li>如何知道一个网站是安全的</li>
<li>SSL证书是什么</li>
<li>SSL是如何工作的</li>
<li>如何给我的网站申请SSL</li>
<li>在哪里申请SSL证书</li>
<li>可以免费获取SSL证书吗</li>
<li>HTTPS和HTTP的主要区别</li>
<li>总结</li>
</ol>
<h2 id="http">什么是HTTP</h2>
<p>超文本传输协议（HTTP）是浏览器和你想要访问的网站（web服务器）之间的一种沟通方法。</p>
<p>协议允许你通过浏览器从服务器获取你想要的信息。</p>
<p>通过类比来了解HTTP和HTTPS是一个很好的办法。我们都知道浏览器和服务器是通过HTTP来进行通信的。HTTP通常是纯文本。就好比世界上大多数人都说英语，如果一个黑客知道怎么说英语，并且黑进了你的电脑，这样他就可以很轻易地获取你的密码。</p>
<p>但是在肯尼亚，我们的母语是图尔卡纳语。如果你不了解这门语言，并且在肯尼亚发现两个图尔卡纳人在对话，你就会听不懂他们在说什么。</p>
<p>这就是HTTPS的精华所在。它做了加密处理，理论上黑客不知道浏览器和服务器之间发生了什么通信。</p>
<p><img src="https://user-images.githubusercontent.com/33565767/178446926-d904cc04-57cd-4427-bdcc-e76c35f8b51b.png" alt="Client to server" title="client/browser communicating with server" width="1054" height="484" loading="lazy"></p>
<p>如果我登陆了<a href="http://www.google.com">http://www.google.com</a>，我会看到谷歌的默认页面。</p>
<p><img src="https://user-images.githubusercontent.com/33565767/178450768-e1fed4a5-993d-4d49-a47f-83cce6473085.png" alt="Googles default page" title="Google's default page" width="1366" height="727" loading="lazy"></p>
<p>客户端（大多数情况下是浏览器）发送一个信息，在计算机术语中叫做请求（request）。然后服务器应答，通常被称为响应（response）。</p>
<p>HTTP可以有效地发送HTML文档、图片和视频到web浏览器，方便用户观看。HTTP同样也使用HTML格式将数据传输到服务器。</p>
<p><img src="https://user-images.githubusercontent.com/33565767/178460366-d0568e2d-d107-4afe-a778-0ce1d224b176.png" alt="Where HTTP Protocol sits" title="HTTP Protocol is between the web browser(client) and the web server, which is in constant communication with the server side script and the database." width="880" height="586" loading="lazy"></p>
<h2 id="http">HTTP如何运作</h2>
<p>HTTP通过纯文本传输数据。举个例子，如果你在访问你的银行网页，这个网页使用的是HTTP，那么黑客就可以访问这个页面，并且读取任何你发送的信息。</p>
<p>此时HTTPS就派上用场了。许多公司都应用了HTTPS，确保用户安全地发送信息。我们会在后文章讨论。</p>
<h2 id="http">HTTP的特征</h2>
<ul>
<li>
<p>纯文本。在HTTP创建之初，开发者们只想解决一个问题：仅服务于文本文件。现在，HTTP已经被运用于文本以外更多地方。</p>
</li>
<li>
<p>七层协议。HTTP是网络通信OSI模型的第七层协议。第七层是应用层，也是OSI模型的最外层。 其他的层级包括物理层、数据链路层、网络层、传输层、会话层和表示层。想要了解更多OSI模型的信息，可以参考这篇<a href="https://chinese.freecodecamp.org/news/osi-model-networking-layers/">文章</a>，以及freeCodeCamp的YouTube频道里由Brain Ferrill讲解的网络工作的视频。视频中包含除了OSI以外更多精彩内容。<a href="https://www.youtube.com/watch?v=qiQR5rTSshw&amp;t=27s&amp;ab_channel=freeCodeCamp.org">Computer Networking Course - Network Engineering [CompTIA Network+ Exam Prep]</a></p>
</li>
<li>
<p>不安全。当你通过纯文本发送HTTP请求的时候，你同样也收到纯文本响应。也就是说任何可以访问这些请求和响应的人都可以读取这些信息。<br>
<img src="https://user-images.githubusercontent.com/33565767/179723161-3ec27c27-df79-4749-b810-974583cf1687.png" alt="Insecure connection" title="Insecure connection during a normal HTTP connection by the user" width="949" height="303" loading="lazy"></p>
</li>
<li>
<p>轻量。HTTP的优势在于轻量。因为没有像HTTPS一样，通过加密来保护数据，所以HTTP传输速度非常快。</p>
</li>
<li>
<p>HTTP通常在端口80监听。</p>
</li>
</ul>
<h2 id="">如何知道一个网站不安全</h2>
<p>当网站不安全的时候，Chrome通常会发出一个警告：<code>Your connection is not private</code>（你的连接不是私人的）。<br>
<img src="https://user-images.githubusercontent.com/33565767/182329336-d405d5b4-f5bb-45df-b936-aa1d04b9dffd.png" alt="HTTP Not secure" title="Your connection is not secure when going to a site that is not secure" width="1365" height="722" loading="lazy"></p>
<p>在Chrome的URL输入框内通常会显示红色的<code>Not Secure</code>（不安全）。<br>
<img src="https://user-images.githubusercontent.com/33565767/182329466-d2db68a8-7033-4f64-bb66-0665e8fc0c62.png" alt="Not secure URL image" title="URL of an insecure website" width="541" height="87" loading="lazy"></p>
<h2 id="http">所有的HTTP网站都不安全吗</h2>
<p>假设你正在浏览一个meme网站，一边滚动图片一边哈哈大笑。如果网站使用的是HTTP协议，这没什么大不了。</p>
<p>这时你觉得有些无聊了，打算登陆你的银行的网站，网站没有使用HTTPS协议，此时你就向黑客双手奉上了你的账户信息。</p>
<p>所以安全的底线是你浏览的信息是否无关紧要。如果不重要，HTTP是安全的，但是如果是需要保密的信息，HTTP就不够用。</p>
<h2 id="https">什么是HTTPS</h2>
<p>超文本传输安全协议，即HTTPS是浏览器和你登陆的网站（服务器）之间安全的通信。</p>
<h2 id="https">HTTPS如何运作</h2>
<p>HTTPS通过加密数据这样的安全协议来确保通信的安全。</p>
<p>对于大多数网站来说，拥有HTTPS的方式是获取一个SSL（Secure Sockets Layer安全套接层）或者TLS（Transport Layer Security传输层安全协议）证书。</p>
<p>现在，SSL已经兼容TLS，所以你没有必要获取一个TLS证书。</p>
<h2 id="https">HTTPS的特证</h2>
<ul>
<li>加密数据。通过TLS/SSL协议来加密数据。</li>
<li>是第四层（传输层）协议。</li>
<li>公钥和私钥的密钥交换发生在HTTPS中以加密和解密数据。</li>
<li>不如HTTP轻量。当HTTPS发生加密和解密的时候，就变得笨重。</li>
<li>HTTPS在端口443监听。</li>
</ul>
<h2 id="">加密的工作原理</h2>
<p><img src="https://user-images.githubusercontent.com/33565767/180215739-5e731309-eda1-4993-927c-c9daa400c3c5.png" alt="How encryption works" title="I am a dev from the client text passing through an encyption" width="977" height="280" loading="lazy"></p>
<p>假设我输入“I am a dev（我是一个开发者）。”当我点击发送的时候，这段文字会被加密，然后在服务器端被解密。</p>
<p>服务器端也是同样的道理。从服务器发送的响应，会先被加密处理然后再到客户端被解密。</p>
<h2 id="">如何知道一个网站是安全的</h2>
<p>检查一个网站是否是安全的，你通常可以查看URL信息栏是否有一把锁。如果有一把锁，则服务器和客户端之间的通信就是安全的。</p>
<p><img src="https://user-images.githubusercontent.com/33565767/178449484-738fb908-901d-4a61-9f8f-fa5a39029012.png" alt="Showing that the site is secure" title="A padlock that shows the site is secure on the URL" width="1144" height="692" loading="lazy"></p>
<p>当你点击这个锁的图标，就会看到安全连接的更多信息。</p>
<p><img src="https://user-images.githubusercontent.com/33565767/180213859-21460cfa-6a8c-484e-81e5-5dba4fc31f2a.png" alt="Shows site is secure" title="The URL section with more details of a secure site" width="1157" height="713" loading="lazy"></p>
<h2 id="ssl">SSL证书是什么</h2>
<p>SSL证书是一个小文件，告诉你的浏览器，比方说，freecodecamp.org是它所声称的网站，并且是可靠的。</p>
<p>证书的认证即是向客户（用户）确认他们所连接的服务器是管理该域（domain）的服务器。认证是为了使用户免受如域名欺骗这样的安全问题的影响。</p>
<p>证书包含一个公钥，并告诉你正在尝试连接的网站的所有者是谁。如果网站没有SSL证书，则无法使用TLS加密。</p>
<p>如果你是网站所有者，你可以创建自己的SSL证书（也称为自签名证书）。但这种方法的问题在于Chrome等浏览器不信任这些证书。它们倾向于信任由证书颁发机构颁发的证书。</p>
<h2 id="ssl">SSL是如何运作的</h2>
<p>SSL加密有两种类型，非对称和对称。SSL加密结合了这两种加密方式。下文会做详细介绍：</p>
<h3 id="">什么是非对称加密</h3>
<p>在非对称加密中，你拥有两把密钥：</p>
<ol>
<li>公钥</li>
<li>私钥</li>
</ol>
<p><img src="https://user-images.githubusercontent.com/33565767/181718454-847858dc-0df5-4bc5-bfaf-b6210c571d8f.png" alt="Asymmetric encryption" title="Asymmetric (Public key) encryption" width="1004" height="469" loading="lazy"></p>
<p>客户端/用户/浏览器在通信的时候给服务器提供公钥，然后通过公钥进行加密，服务器通过私钥进行解密。</p>
<p>私钥只能在该特定服务器上找到，其他任何人都没有。这就是为什么非对称加密更强大且更难破解，因为它有两个不同的密钥，私钥和公钥。这两个密钥协同工作以确保数据更安全。</p>
<p>这也是为什么这种加密的长度是1024/2048位。</p>
<h3 id="">什么是对称加密</h3>
<p>对称加密就简单很多。你只有一把密钥。客户端使用一个密钥进行加密，服务器使用相同的密钥解密数据。</p>
<p>对称加密更轻量。长度为128/256位。但与非对称相比，它更容易被入侵，这并不意味着它没有用。当我们使用SSL时，我们将非对称和对称结合起来，能够使通信更安全、更私密。</p>
<p><img src="https://user-images.githubusercontent.com/33565767/181720497-326e0dd9-5e0b-4bfb-b01a-2effec5ab9e0.png" alt="Symmetric encryption" title="How symmetric encryption works by using one key on the client side to encrypt and the same key on the server side to decrypt" width="1024" height="332" loading="lazy"></p>
<h3 id="">非对称 + 对称加密的工作原理</h3>
<p>非对称和对称的组合形成双层防护墙<br>
<img src="https://user-images.githubusercontent.com/33565767/182565306-224f199a-da88-4a68-be81-707636cc1069.png" alt="Asymmetric and Symmetric" title="How asymmetric and symmetric encryption work by client first sending a Hello to the server. The server then sends to the client, its public key and certificate in response. The client on step 3, sends a session key that is encrypted using the public key. On step 4, the server will decrypt the session key using the server's private key. Finally, step 5, the connection is established between the client and the server." width="945" height="563" loading="lazy"></p>
<p>在第一步中，服务器向浏览器发送非对称的公钥。如我们所知，非对成密匙包含一个公钥和一个私钥，因此浏览器收到公钥。</p>
<p>之后，浏览器生成一个会话密钥。</p>
<p>对称加密中客户端和服务器都只使用一个密钥。所以接下来，浏览器将生成一个本地会话密钥，是一个对称加密会话密钥。然后它将使用第一步中的非对称公钥对其进行加密。本地生成的会话密钥与公钥组合，发送到服务器。</p>
<p>然后，服务器将使用私钥解密它收到的加密会话密钥。在这个特定步骤中，服务器将使用非对称私钥来解密它收到的会话密钥。</p>
<p>现在，一旦解密发生，服务器和浏览器将使用会话密钥进行通信。会话密钥将仅用于这次特定会话。</p>
<p>假设你关闭了浏览器，并在第二天登录 —— 一切重新开始，会话密钥会再次被创建。</p>
<h2 id="ssl">如何给我的网站申请SSL</h2>
<p>如果你是网站所有者，你可以从证书颁发机构获取SSL证书。</p>
<p>然后在托管网站的Web服务器上安装证书。大多数情况下，托管网站的托管公司会为你处理此过程。</p>
<h2 id="ssl">在哪里申请SSL证书</h2>
<p>有些组织颁发安全证书，这些组织称为证书颁发机构。其中一些证书颁发机构包括：DigiCert、Comodo等。</p>
<p>许多开发人员从这些组织获得证书。由于这些组织办法的证书是使用最广泛，浏览器通常信任来自这些组织的证书。</p>
<h2 id="ssl">可以免费获取SSL证书吗</h2>
<p>Cloudflare免费提供SSL证书。它是最早采取这一行动的互联网安全公司之一。</p>
<p>如果你想申请一个，<a href="https://www.cloudflare.com/ssl/">可以点击这里</a>。</p>
<h2 id="https">HTTPS的用途</h2>
<p>HTTPS在安全性方面起到了很大的作用。没有它，传递敏感信息将成为一个巨大的挑战，尤其是当你的企业需要一种安全的通信方式时。</p>
<p>接受在线支付的网站（如电子商务网站）通常需要HTTPS。这是为了避免信用卡详细信息和登录信息等被盗 (引用: <a href="https://www.entrepreneur.com/article/281633">Tony Messer</a>)。</p>
<h2 id="httpshttp">HTTPS和HTTP的主要区别</h2>
<ul>
<li>HTTPS中启用了加密层，而HTTP中没有加密层。</li>
<li>数据在HTTPS中受到保护，而在HTTP中则不受保护。</li>
<li>当使用HTTPS时，网站在Google中的排名会提高，而使用HTTP时，不会获得任何排名提升。</li>
<li>使用HTTPS可以防止网络钓鱼，而使用HTTP没有保护。</li>
<li>使用HTTPS符合支付行业规定，但是HTTP不合规。</li>
<li>在最初几秒钟内加载HTTPS可能比加载HTTP慢。</li>
<li>获得SSL证书可能需要花钱，而HTTP没有认证成本。</li>
<li>在chrome上使用HTTPS网站更方便，使用HTTP网站会经常收到不安全提示。</li>
</ul>
<h2 id="">总结</h2>
<p>HTTP和HTTPS在开发者的日常生活中扮演了重要的角色，浏览器和服务器之间的通信是我们工作的动力。</p>
<p>尽可能地保护用户的数据，以防止他们的信息被盗，将获得用户的信任并提供更好的用户体验。</p>
<p>下篇文章见。</p>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ HTTP 请求方法——用代码示例解释 Get vs Put vs Post ]]>
                </title>
                <description>
                    <![CDATA[ 原文：HTTP Request Methods – Get vs Put vs Post Explained with Code Examples [https://www.freecodecamp.org/news/http-request-methods-explained/]，作者：Camila Ramos Garzon [https://www.freecodecamp.org/news/author/camiinthisthang/] 在本文中，我们将讨论 get、put 和 post HTTP 方法，介绍每种 HTTP 方法的用途以及使用场景。 为了深入了解 HTTP 方法的工作原理，本文还将介绍 HTTP 有关上下文和背景信息。 这篇文章讲要介绍的主题：  * HTTP 协议  * 客户端-服务器架构  * APIs 读完本文，将对每个请求方法的定位有一个很好的了解。还将具备发起请求和使用 Web API 的经验。 什么是 HTTP？ HTTP 是一种协议，或一组明确的规则，用于访问网络上的资源。资源可以是任何东西，从 HTML ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/http-request-methods-explained/</link>
                <guid isPermaLink="false">624ab07e99ec7406219e5564</guid>
                
                    <category>
                        <![CDATA[ HTTP ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ ZhichengChen ]]>
                </dc:creator>
                <pubDate>Mon, 04 Apr 2022 04:30:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2022/04/FCC-Cover-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>原文：<a href="https://www.freecodecamp.org/news/http-request-methods-explained/">HTTP Request Methods – Get vs Put vs Post Explained with Code Examples</a>，作者：<a href="https://www.freecodecamp.org/news/author/camiinthisthang/">Camila Ramos Garzon</a></p><!--kg-card-begin: markdown--><p>在本文中，我们将讨论 get、put 和 post HTTP 方法，介绍每种 HTTP 方法的用途以及使用场景。</p>
<p>为了深入了解 HTTP 方法的工作原理，本文还将介绍 HTTP 有关上下文和背景信息。</p>
<h3 id="">这篇文章讲要介绍的主题：</h3>
<ul>
<li>HTTP 协议</li>
<li>客户端-服务器架构</li>
<li>APIs</li>
</ul>
<p>读完本文，将对每个请求方法的定位有一个很好的了解。还将具备发起请求和使用 Web API 的经验。</p>
<h2 id="http">什么是 HTTP？</h2>
<p>HTTP 是一种协议，或一组明确的规则，用于访问网络上的资源。资源可以是任何东西，从 HTML 文件到数据库中的数据、照片、文本等等。</p>
<p>通过 HTTP 协议向这些 API 发出请求，然后返回相应的资源。<code>API</code>代表应用程序编程接口。它是开发人员请求资源的机制。</p>
<h3 id="">客户端-服务器架构</h3>
<p>学习 HTTP 方法前，理解客户端/服务器架构的概念很重要。该架构描述了 Web 应用程序的工作方式，并定义了通信的规则。</p>
<p>客户端是用户实际与之交互的应用程序，它展示所需的内容。服务器是将内容或资源发送到客户端的应用程序。服务器在某处持续运行等待客户端的请求。</p>
<p>这种分离的主要原因是为了保护敏感信息。如果整个应用程序都被下载到浏览器中，任何访问网页的人都可以访问所有数据。</p>
<p>这种架构有助于保护 API 密钥、个人数据等。现在，<a href="https://nextjs.org/">Next.js</a> 和 <a href="https://www.netlify.com/">Netlify</a> 等流行工具允许开发人员在与其客户端程序中运行服务器代码， 无需部署到专用的服务器上。</p>
<h3 id="">客户端-服务器通信</h3>
<p>客户端和服务器根据需要每次单独发送消息进行通信，而不是持续的流通信。</p>
<p>这些通信几乎总是由客户端以请求的形式发起。这些请求由服务器应用程序完成，返回包含请求的资源的响应。</p>
<h3 id="">为什么我们需要服务器-客户端架构？</h3>
<p>假设正在构建一个网络天气应用。用户要与之交互的是客户端程序——它有按钮、搜索栏，并显示城市名称、当前温度、AQI 等数据。</p>
<p>天气应用不会将每个城市及其天气信息直接硬编码到程序中。这会使应用程序变得臃肿而缓慢，检索数据添加到数据库需要花费很长时间，而且每天的更新的也很让人头疼。</p>
<p>相反，该应用程序可以使用 Weather Web API 按城市访问天气数据。应用程序会收集用户的位置，然后向服务器发出请求，说：“嘿，把这个城市的天气信息发给我。”</p>
<p>根据要实现的目标，将使用不同的请求方法。服务器返回一个包含天气信息等内容的响应，具体取决于 API 的设计。它还可能会返回时间戳、该城市所在的区域等信息。</p>
<p>客户端与运行在某处的服务器进行通信，服务器的工作就是不断地到监听是否有到该地址的请求。当它接收到请求时，它会基于传入的参数从数据库或者另一个 API 或者本地文件查询返回符合要求的响应。</p>
<h3 id="http">HTTP 请求剖析</h3>
<p>HTTP 请求必须具有以下内容：</p>
<ul>
<li>HTTP 方法（如 <code>GET</code>）</li>
<li>主机 URL（如<code>https://api.spotify.com/</code>）</li>
<li>端点路径（如 <code>v1/artists/{id}/related-artists</code>）</li>
</ul>
<p>请求还可选包含：</p>
<ul>
<li>Body 请求体</li>
<li>Headers</li>
<li>查询字符串</li>
<li>HTTP 版本号</li>
</ul>
<h3 id="http">HTTP 响应剖析</h3>
<p>响应必须具有以下内容：</p>
<ul>
<li>协议版本（如<code>HTTP/1.1</code>）</li>
<li>状态码（如 <code>200</code>）</li>
<li>状态文本（<code>OK</code>）</li>
<li>Headers</li>
</ul>
<p>响应还可选具有：</p>
<ul>
<li>Body 响应体</li>
</ul>
<h2 id="http">HTTP 方法解释</h2>
<p>Post Malone 意味着 Get、Put、Patch 和 Delete Malone 的存在。</p>
<p>— Paul Ford (@ftrain) <a href="https://twitter.com/ftrain/status/1195350262145306624?ref_src=twsrc%5Etfw">November 15, 2019</a></p>
<p>现在我们知道了什么是 HTTP 以及为什么需要它，让我们来聊聊这些不同的 HTTP 方法。</p>
<p>在上面的天气应用程序示例中，我们想要检索某城市的天气信息。但是如果我们想提交一个城市的天气信息该如何请求呢？</p>
<p>在现实生活中，可能无权更改其他人的数据，但假设我们是社区运行的天气应用程序的贡献者。除了从 API 获取天气信息外，该城市的成员还可以更新此信息以显示更准确的数据。</p>
<p>或者，如果我们想完全添加一个由于某种原因在我们的城市数据库中不存在的新城市怎么办？ 这些是不同的功能——检索数据、更新数据、创建新数据——所有这些都有对应的 HTTP 方法。</p>
<h3 id="httppost">HTTP POST 请求</h3>
<p><code>POST</code> 用来创建一个新资源。<code>POST</code> 请求需要一个请求体，可以在其中定义要创建的实体数据。</p>
<p>POST 请求成功返回的状态码是 200。在天气应用中，可以使用 POST 方法来添加新城市。</p>
<h3 id="httpget">HTTP GET 请求</h3>
<p><code>GET</code> 用来读取或检索资源。 <code>GET</code> 成功后会返回包含所请求信息的响应。</p>
<p>在天气应用中，可以使用 GET 来检索某城市当前的天气。</p>
<h3 id="httpput">HTTP PUT 请求</h3>
<p><code>PUT</code> 用来修改资源。<code>PUT</code> 用请求体 payload 中的数据替换整个资源。如果没有与请求体唯一标识相匹配的资源，它将创建一个新资源。</p>
<p>在天气应用中，可以使用 <code>PUT</code> 来更新指定城市的所有天气数据。</p>
<h3 id="httppatch">HTTP PATCH 请求</h3>
<p><code>PATCH</code> 用来修改资源的部分字段。使用 <code>PATCH</code>，只需要传入想要更新的字段即可。</p>
<p>在天气应用中，可以使用 <code>PATCH</code> 来更新指定城市指定日期的降雨量。</p>
<h3 id="http">HTTP 删除请求</h3>
<p><code>DELETE</code> 可以用来删除资源。在天气应用中，可以使用 <code>DELETE</code> 删除出于某种原因不再想跟踪的城市。</p>
<h2 id="httpmethods">HTTP Methods 常见问题解答</h2>
<h3 id="putpost">PUT 和 POST 有什么区别？</h3>
<p><code>PUT</code> 请求是幂等的，这意味着执行相同的 <code>PUT</code> 请求将始终产生相同的结果。</p>
<p>另一方面，<code>POST</code> 会产生不同的结果。如果多次执行 <code>POST</code> 请求，将多次创建新资源，尽管传入的是相同的数据。</p>
<p>使用餐厅类比，多次 <code>POST</code> 会创建多个独立的订单，而多次 <code>PUT</code> 请求将更新现有的订单。</p>
<h3 id="putpatch">PUT 和 PATCH 有什么区别？</h3>
<p>主要区别在于，如果 <code>PUT</code> 找不到指定的资源，它将创建一个新资源。而使用 <code>PUT</code> 时，需要传入改数据的全部资源，即使只想修改一个字段。</p>
<p>使用 <code>PATCH</code>，可以只传入要更新字段更新资源。</p>
<h3 id="put">如果我只想更新我的部分资源怎么办？我还能使用 PUT 吗？</h3>
<p>如果只想更新部分资源，则在发出 <code>PUT</code> 请求时仍需要发送整个资源的数据。这里更适合的选项是 <code>PATCH</code>。</p>
<h3 id="body">为什么请求和响应的 body 是可选的？</h3>
<p>body 是可选的，因为对于某些请求，例如使用 <code>GET</code> 方法检索资源，请求正文中无需指定任何内容。可以从指定端点检索所有数据。</p>
<p>类似地，当状态码足够或正文中没有要返回的内容时，某些响应的主体是可选的，如 <code>DELETE</code> 操作。</p>
<h2 id="http">HTTP 请求示例</h2>
<p>现在已经介绍了什么是 HTTP 请求，以及它们的使用场景，让我们发起一些请求！这里将使用 <a href="https://docs.github.com/en/rest/reference/gists">GitHub Gist API</a>。</p>
<p>“Gist 是一种与他人共享代码段的简单方法。所有 Gist 都是 Git 仓库，因此可以使用 Git 的版本控制，fork 等功能。” （来源：GitHub）</p>
<p>为此，需要一个 GitHub 帐户。如果还没有，这是一个很好的时机来创建一个以在将来保存代码。</p>
<p>GitHub 上的每个用户都可以创建 gist、检索他们的 gist、检索所有公共 gist、删除 gist 和更新 gist，等等。为了简单起见，我们将使用 <a href="https://hoppscotch.io/">Hoppscotch</a>，这是一个可以方便地发起 HTTP 请求的一个可视化平台。</p>
<p>快速上手 Hoppscotch：</p>
<ul>
<li>有一个下拉菜单，可以在其中选择要用来创建请求的 method。</li>
<li>有一个文本框，可以在其中粘贴要访问的 API 端点的 URL。</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-24-at-12.35.33-PM.png" alt="Screen-Shot-2022-01-24-at-12.35.33-PM" width="600" height="400" loading="lazy"></p>
<ul>
<li>有一个 Headers 部分，我们将按照 GitHub 文档的说明在其中传递请求头。</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-24-at-12.39.38-PM-1.png" alt="Screen-Shot-2022-01-24-at-12.39.38-PM-1" width="600" height="400" loading="lazy"></p>
<ul>
<li>有一个 body 区域，可以按照 GitHub 文档的指示将相应的请求实体写入 body。</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-24-at-12.41.14-PM.png" alt="Screen-Shot-2022-01-24-at-12.41.14-PM" width="600" height="400" loading="lazy"></p>
<ul>
<li>如果请求成功，右栏会显示通知。如果它是绿色的，表示成功发起了请求，如果它是红色的，代表有错误。</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-24-at-3.44.56-PM.png" alt="Screen-Shot-2022-01-24-at-3.44.56-PM" width="600" height="400" loading="lazy"></p>
<h3 id="get">如何发出 GET 请求</h3>
<p>要创建 <code>GET</code> 请求以检索所有特定用户的 gists，可以使用以下方法和端点：<code>GET /users/{username}/gists</code>。按照文档可以通过 endpoint 传入指定的参数来发起请求。</p>
<p>可以看到在路径中需要传入一个带有目标用户用户名的字符串。还需要传入一个名为 accept 的 headers 并将其设置为 <code>application/vnd.github.v3+json</code>。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-20-at-2.01.35-PM.png" alt="Screen-Shot-2022-01-20-at-2.01.35-PM" width="600" height="400" loading="lazy"></p>
<p>API 的 URL 为：</p>
<pre><code class="language-shell">https://api.github.com
</code></pre>
<p>此特定操作的端点路径为：</p>
<pre><code>/users/{username}/gists
</code></pre>
<p>要发起此请求：</p>
<ol>
<li>在 Hoppscotch 的输入字段中粘贴完整的 URL + 路径。请务必将 “username” 替换为实际用户名。如果还没有创建过 Gists 的 GitHub 账号，可以先使用我的：camiinthisthang。</li>
<li>选择<code>GET</code>请求方法</li>
<li>在 Headers 选项卡中，将 accept 设置为 header 并将值设置为 <code>application/vnd.github.v3+json</code></li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-24-at-12.39.38-PM-2.png" alt="Screen-Shot-2022-01-24-at-12.39.38-PM-2" width="600" height="400" loading="lazy"></p>
<p>4. 点击发送！</p>
<p>在底部，会看到格式为 <code>JSON</code> 的响应。为了便于阅读，复制响应并将其粘贴到 <a href="https://jsonformatter.curiousconcept.com/#">在线 JSON 格式化程序</a>。</p>
<p>在格式化程序中，可以知道响应是一个对象数组。每个对象代表一个 gist，向我们展示 URL、ID 等信息。</p>
<h3 id="post">如何发出 POST 请求</h3>
<p>现在来使用 <code>POST</code> 方法创建一个资源。在这种情况下，新资源将是一个新的 gist。</p>
<p>首先，需要创建一个个人 access token。为此，<a href="https://github.com/settings/tokens">转到设置页面</a>并点击生成令牌。</p>
<p>命名 token 并选择 scope “Create Gists”：</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-20-at-2.59.11-PM.png" alt="Screen-Shot-2022-01-20-at-2.59.11-PM" width="600" height="400" loading="lazy"></p>
<p>然后单击页面底部的绿色 <code>Generate token</code> 按钮。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-20-at-3.28.01-PM.png" alt="Screen-Shot-2022-01-20-at-3.28.01-PM" width="600" height="400" loading="lazy"></p>
<p>复制 access 代码并将其粘贴到合适的位置。</p>
<p>现在准备好发起的请求了！根据文档应该在 body 中传递一个 headers 和一个 <code>files</code> 对象。可选传入一些其他参数，包括一个布尔值，它代表这个 gist 是公共的还是私有的。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-20-at-2.07.23-PM.png" alt="Screen-Shot-2022-01-20-at-2.07.23-PM" width="600" height="400" loading="lazy"></p>
<p>API 的 URL 如下：</p>
<pre><code class="language-shell">https://api.github.com
</code></pre>
<p>此操作的端点路径如下：</p>
<pre><code>/gists
</code></pre>
<p>要发起此请求：</p>
<ol>
<li>
<p>将完整的 URL + 路径粘贴到 Hoppscotch 的输入字段中。</p>
</li>
<li>
<p>选择<code>POST</code>请求方法</p>
</li>
<li>
<p>在 Headers 选项卡中，将 accept 设置为 header 并将值设置为 <code>application/vnd.github.v3+json</code></p>
</li>
<li>
<p>在 Body 选项卡中，将内容类型设置为 <code>application/json</code>。然后从一个对象<code>{}</code>开始。</p>
<p>在这个对象内部，将 public <code>boolean</code> 设置为 <code>true</code>。然后将定义属性 <code>files</code>，其值是另一个对象，其键名是新 gist 名称。值应该是另一个其键为 <code>content</code> 的对象。这里的值应该是想要实际添加到要点中的任何值。</p>
<p>可以复制/粘贴以下代码：</p>
</li>
</ol>
<pre><code class="language-javascript">{
  "public": true, 
  "files": {
    "postgist.txt": {
      "content": "Adding a GIST via the API!!"
    }
  }
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-24-at-2.35.57-PM.png" alt="Screen-Shot-2022-01-24-at-2.35.57-PM" width="600" height="400" loading="lazy"></p>
<p>5. 在 Authorization 选项卡中，将授权类型设置为 <code>Basic Auth</code>。输入 GitHub 用户名并传入在密码字段中创建的个人访问令牌。</p>
<p>在执行这个之后，会得到一个很长的响应。检查 gist 是否已创建的一种简单方法是访问 GitHub 中的 Gist。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-24-at-2.39.27-PM.png" alt="Screen-Shot-2022-01-24-at-2.39.27-PM" width="600" height="400" loading="lazy"></p>
<p>可以看到成功添加了一个 Gist！</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-24-at-2.39.58-PM.png" alt="Screen-Shot-2022-01-24-at-2.39.58-PM" width="600" height="400" loading="lazy"></p>
<h3 id="patch">如何创建 PATCH  请求</h3>
<p>来更新刚刚创建的 Gist 的标题和描述。请记住：<code>PATCH</code> 允许更新资源的一部分，而不是整个资源。我们没有传入的任何内容都将保持不变。</p>
<p>在创建 Gist 时实际上并没有提供描述，因此我们可以使用 patch 创建一个。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-20-at-3.35.56-PM.png" alt="Screen-Shot-2022-01-20-at-3.35.56-PM" width="600" height="400" loading="lazy"></p>
<p>API 的 URL：</p>
<pre><code class="language-shell">https://api.github.com
</code></pre>
<p>此特定操作的端点路径如下：</p>
<pre><code>/gists/{gist_id}
</code></pre>
<p>要创建此请求：</p>
<ol>
<li>在 Hoppscotch 的输入字段中粘贴完整的 URL + 路径。获取要更新的 gist 的 <code>Gist ID</code>。可以通过转到 GitHub 中的 Gist 并复制 URL 末尾的字母数字字符串来找到 ID。</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-20-at-3.50.13-PM.png" alt="Screen-Shot-2022-01-20-at-3.50.13-PM" width="600" height="400" loading="lazy"></p>
<p>2.  选择 <code>PATCH</code> 请求方法。</p>
<p>3.   在 Headers 选项卡中，将 accept 设置为 header 并将值设置为 <code>application/vnd.github.v3+json</code>。</p>
<p>4.   在 Authorization 选项卡中，将授权类型设置为 <code>Basic Auth</code>。输入 GitHub 用户名并传递我们在密码字段中创建的个人 access token。</p>
<p>5.   在 Body 选项卡中，传入更新后的描述和标题。代码如下：</p>
<pre><code class="language-javascript">{
  "description": "Adding a description via the API", 
  "files": {
    "postgist.txt": {
      "content": "Adding a GIST via the API!! -- adding this line at the end to make the content slightly longer"
    }
  }
}
</code></pre>
<p>刷新 Gist，会看到标题和描述已经更新！</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-24-at-3.38.35-PM.png" alt="Screen-Shot-2022-01-24-at-3.38.35-PM" width="600" height="400" loading="lazy"></p>
<h3 id="delete">如何发起  DELETE 请求</h3>
<p>要删除创建的 Gist。应该传入 header 和 Gist ID。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-24-at-3.42.30-PM.png" alt="Screen-Shot-2022-01-24-at-3.42.30-PM" width="600" height="400" loading="lazy"></p>
<p>API 的 URL 如下：</p>
<pre><code class="language-shell">https://api.github.com
</code></pre>
<p>此特定操作的端点路径如下：</p>
<pre><code>/gists/{gist_id}
</code></pre>
<p>要创建此请求：</p>
<ol>
<li>在 Hoppscotch 的输入字段中粘贴完整的 URL + 路径。获取要更新的 gist 的 <code>Gist ID</code> 。可以通过转到 GitHub 中的 Gist 并复制 URL 末尾的字母数字字符串来找到 ID。</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Screen-Shot-2022-01-20-at-3.50.13-PM.png" alt="Screen-Shot-2022-01-20-at-3.50.13-PM" width="600" height="400" loading="lazy"></p>
<p>2.   选择 <code>DELETE</code> 请求方法</p>
<p>3.  在 Headers 选项卡中，将 accept 设置为 header 并将值设置为 <code>application/vnd.github.v3+json</code>。</p>
<p>导航到 Gists，会看到已经成功地删除了该资源。</p>
<h3 id="">如何在程序中发起请求</h3>
<p>使用 Hoppscotch 是因为它可以方便的发起请求，而无需启动程序或下载任何内容。</p>
<p>如果想在 JavaScript/React 应用程序中发出请求，可以使用 <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch">Javascript fetch</a> 或 <a href="https://axios-http.com/docs/intro">Axios</a>。</p>
<p>有关如何发起使用 HTTP 请求方法和 API 的简单应用程序的步骤演示，<a href="https://www.youtube.com/watch?v=7xu7FnKh54M&amp;t=334s">可以查看我在 youtube 上的视频，我们在其中创建了一个 Web 应用程序，该应用程序通过 API 显示有关所有国家/地区的信息 .</a></p>
<h2 id="">你做到了！</h2>
<p>如果你正在阅读本文，请继续给自己点赞，因为你已经了解了 Web API、HTTP 协议、客户端-服务器架构——并且还发起了第一个请求。</p>
<p>如果你喜欢我的风格，可以在 <a href="https://www.youtube.com/channel/UCyEnr-lcCUavJzh0uodvG3w">YouTube</a>、[Tik Tok](https:// www.tiktok.com/@camiinthisthang?)、<a href="https://twitter.com/camiinthisthang">Twitter</a> 和 <a href="https://hashnode.com/@camiinthisthang">Hashnode</a> 找到我。还可以通过 <a href="https://camiinthisthang.dev/">我的个人网站</a> 找到代码片段和联系我的方式。</p>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 详解 HTTP、HTTPS 和 HTTP2 ]]>
                </title>
                <description>
                    <![CDATA[ 你知道 HTTP 和 HTTPS 的区别吗？如果你想了解更多的计算机网络基础知识，那么你可能会想弄清楚这些概念。 在这篇文章中，我将尽量用通俗易懂的方式来向读者讲述 HTTP 的知识。我建议大家在学习 HTTP 知识的时候，利用 Chrome 开发者工具来做实践，这可以帮助我们理解得更深刻。 此图是在网上找来的，侵删HTTP 概述 HTTP 超文本传输​​协议是位于 TCP/IP 体系结构中的应用层协议，它是万维网数据通信的基础。 当我们访问一个网站时，需要通过统一资源定位符（uniform resource locator，URL）来定位服务器并获取资源。 <协议>://<域名>:<端口>/<路径> 一个 URL 的一般形式通常如上所示（http://test.com/index.html ），现在最常用的协议就是 HTTP，HTTP 的默认端口是 80，通常可以省略。 HTTP/1.1 HTTP/1.1 是目前使用最广泛的版本，一般没有特别标明版本都是指 HTTP/1.1。 HTTP 连接建立过程 我们来看一下在浏览器输入 URL 后获取 HTML 页面的过程。   ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/http-https-and-http2/</link>
                <guid isPermaLink="false">5fb235e95f583f056509114b</guid>
                
                    <category>
                        <![CDATA[ HTTP ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTTPS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ 计算机网络 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ woai3c ]]>
                </dc:creator>
                <pubDate>Thu, 19 Aug 2021 07:20:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/04/photo-1593642533144-3d62aa4783ec-1.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>你知道 HTTP 和 HTTPS 的区别吗？如果你想了解更多的计算机网络基础知识，那么你可能会想弄清楚这些概念。</p><p>在这篇文章中，我将尽量用通俗易懂的方式来向读者讲述 HTTP 的知识。我建议大家在学习 HTTP 知识的时候，利用 Chrome 开发者工具来做实践，这可以帮助我们理解得更深刻。</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://pic2.zhimg.com/80/v2-8d547f61a175c4e6cc05ad90a7406791_720w.jpg" class="kg-image" alt="v2-8d547f61a175c4e6cc05ad90a7406791_720w" width="600" height="400" loading="lazy"><figcaption>此图是在网上找来的，侵删</figcaption></figure><h2 id="http-">HTTP 概述</h2><p>HTTP 超文本传输​​协议是位于 TCP/IP 体系结构中的应用层协议，它是万维网数据通信的基础。</p><p>当我们访问一个网站时，需要通过统一资源定位符（uniform resource locator，URL）来定位服务器并获取资源。</p><pre><code class="language-text">&lt;协议&gt;://&lt;域名&gt;:&lt;端口&gt;/&lt;路径&gt;</code></pre><p>一个 URL 的一般形式通常如上所示（<code>http://test.com/index.html</code> ），现在最常用的协议就是 HTTP，HTTP 的默认端口是 80，通常可以省略。</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-91035fa397152281c18e1a2f9ece81f4_720w.jpg" class="kg-image" alt="v2-91035fa397152281c18e1a2f9ece81f4_720w" width="600" height="400" loading="lazy"></figure><h2 id="http-1-1">HTTP/1.1</h2><p>HTTP/1.1 是目前使用最广泛的版本，一般没有特别标明版本都是指 HTTP/1.1。</p><h3 id="http--1">HTTP 连接建立过程</h3><p>我们来看一下在浏览器输入 URL 后获取 HTML 页面的过程。</p><ol><li>先通过<a href="https://link.zhihu.com/?target=https%3A//baike.baidu.com/item/%25E5%259F%259F%25E5%2590%258D%25E7%25B3%25BB%25E7%25BB%259F%25EF%25BC%2588%25E6%259C%258D%25E5%258A%25A1%25EF%25BC%2589%25E5%258D%258F%25E8%25AE%25AE/15134609%3Ffromtitle%3Ddns%26fromid%3D427444" rel="nofollow noreferrer">域名系统（Domain Name System，DNS）</a>查询将域名转换为 IP 地址。即将 <code>test.com</code> 转换为 <code>221.239.100.30</code> 这一过程。</li><li>通过三次握手（稍后会讲）建立 TCP 连接。</li><li>发起 HTTP 请求。</li><li>目标服务器接收到 HTTP 请求并处理。</li><li>目标服务器往浏览器发回 HTTP 响应。</li><li>浏览器解析并渲染页面。</li></ol><p>下图中的 RTT 为往返时延（Round-Trip Time： 往返时延。表示从发送端发送数据开始，到发送端收到来自接收端的确认，总共经历的时延）。<br></p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-ddcb4a085bbde7f8bf80f792d4ac7e48_720w.jpg" class="kg-image" alt="v2-ddcb4a085bbde7f8bf80f792d4ac7e48_720w" width="600" height="400" loading="lazy"></figure><h3 id="http--2">HTTP 连接拆除过程</h3><p>所有 HTTP 客户端（浏览器）、服务器都可在任意时刻关闭 TCP 连接。通常会在一条报文结束时关闭连接，但出错的时候，也可能在首部行的中间或其他任意位置关闭连接。</p><h3 id="tcp-">TCP 三次握手和四次挥手</h3><p>由于 HTTP 是基于 TCP 的，所以打算在这补充一下 TCP 连接建立和拆除的过程。</p><p>首先，我们需要了解一些 TCP 报文段的字段和标志位：</p><ol><li>32 比特的序号字段和确认号字段，TCP 字节流每一个字节都按顺序编号。确认号是接收方期望从对方收到的下一字节的序号。</li><li>ACK 标志位，用于指示确认字段中的值是有效的 ACK=1 有效，ACK=0 无效。</li><li>SYN 标志位，用于连接建立，SYN 为 1 时，表明这是一个请求建立连接报文。</li><li>FIN 标志位，用于连接拆除，FIN 为 1 时，表明发送方数据已发送完毕，并要求释放连接。<br></li></ol><figure class="kg-card kg-image-card"><img src="https://pic4.zhimg.com/80/v2-578eeb6309c44c4607344fe019dff19b_720w.jpg" class="kg-image" alt="v2-578eeb6309c44c4607344fe019dff19b_720w" width="600" height="400" loading="lazy"></figure><h3 id="tcp--1">TCP 三次握手建立连接</h3><p>TCP 标准规定，ACK 报文段可以携带数据，但不携带数据就不用消耗序号。</p><ol><li>客户端发送一个不包含应用层数据的 TCP 报文段，首部的 SYN 置为 1，随机选择一个初始序号（一般为 0）放在 TCP 报文段的序号字段中。（SYN 为 1 的时候，不能携带数据，但要消耗掉一个序号）</li><li>TCP 报文段到达服务器主机后，服务器提取报文段，并为该 TCP 连接分配缓存和变量。然后向客户端发送允许连接的 ACK 报文段（不包含应用层数据）。这个报文段的首部包含 4 个信息：ACK 置 为 1，SYN 置为 1；确认号字段置为客户端的序号 + 1；随机选择自己的初始序号（一般为 0）。</li><li>收到服务器的 TCP 响应报文段后，客户端也要为该 TCP 连接分配缓存和变量，并向服务器发送一个 ACK 报文段。这个报文段将服务器端的序号 + 1 放置在确认号字段中，用来对服务器允许连接的报文段进行响应，因为连接已经建立，所以 SYN 置为 0。最后一个阶段，报文段可以携带客户到服务器的数据。并且以后的每一个报文段，SYN 都置为 0。</li></ol><p>下图是一个具体的示例：<br></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://pic2.zhimg.com/80/v2-eb4981e4f58f1822c00d7d290d14ee51_720w.jpg" class="kg-image" alt="v2-eb4981e4f58f1822c00d7d290d14ee51_720w" width="600" height="400" loading="lazy"><figcaption>此截图是我使用 Wireshark 抓包工具截取的 TCP 报文段截图</figcaption></figure><h3 id="tcp--2">TCP 四次挥手拆除连接</h3><p>FIN 报文段即使不携带数据，也要消耗序号。</p><ol><li>客户端发送一个 FIN 置为 1 的报文段。</li><li>服务器回送一个确认报文段。</li><li>服务器发送 FIN 置为 1 的报文段。</li><li>客户端回送一个确认报文段。</li></ol><h3 id="tcp--3">TCP 为什么是四次挥手，而不是三次？</h3><ol><li>当 A 给 B 发送 FIN 报文时，代表 A 不再发送报文，但仍可以接收报文。</li><li>B 可能还有数据需要发送，因此先发送 ACK 报文，告知 A “我知道你想断开连接的请求了”。这样 A 便不会因为没有收到应答而继续发送断开连接的请求（即 FIN 报文）。</li><li>B 在处理完数据后，就向 A 发送一个 FIN 报文，然后进入 LAST_ACK 阶段（超时等待）。</li><li>A 向 B 发送 ACK 报文，双方都断开连接。</li></ol><p>参考资料：</p><ul><li><a href="https://www.zhihu.com/question/63264012">知乎网友-魔方的回答</a></li></ul><h3 id="http--3">HTTP 报文格式</h3><p>HTTP 报文由请求行、首部、实体主体组成，它们之间由 CRLF（回车换行符） 分隔开。</p><p><strong>注意：实体包括首部(也称为实体首部)和实体主体，sp 即是空格 space</strong>。<br></p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-392bc8d0de5ac6d44dd520ca4e42afc8_720w.jpg" class="kg-image" alt="v2-392bc8d0de5ac6d44dd520ca4e42afc8_720w" width="600" height="400" loading="lazy"></figure><p><br>请求行和首部是由 ASCII 文本组成的，实体主体是可选的，可以为空也可以是任意二进制数据。</p><p>请求报文和响应报文的格式基本相同。</p><p><strong>请求报文格式</strong>：</p><pre><code class="language-text">&lt;method&gt; &lt;request-URL&gt; &lt;version&gt;
&lt;headers&gt;
&lt;entity-body&gt;</code></pre><p><strong>响应报文格式</strong>：</p><pre><code class="language-text">&lt;version&gt; &lt;status&gt; &lt;reason-phrase&gt;
&lt;headers&gt;
&lt;entity-body&gt;</code></pre><p><strong>一个请求或响应报文由以下字段组成</strong>：</p><ol><li>请求方法，客户端希望服务器对资源执行的动作。</li><li>请求 URL，命名了所请求的资源。</li><li>协议版本，报文所使用的 HTTP 版本。</li><li>状态码，这三位数字描述了请求过程中所发生的情况。</li><li>原因短语，数字状态码的可读版本（例如上面的响应示例跟在 200 后面的 OK，一般按规范写最好）。</li><li>首部，可以有零或多个首部。</li><li>实体的主体部分，可以为空也可以包含任意二进制数据。</li></ol><p><strong>一个 HTTP 请求示例</strong>：</p><pre><code class="language-text">GET /2.app.js HTTP/1.1
Host: 118.190.217.8:3389
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36
Accept: */*
Referer: http://118.190.217.8:3389/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9</code></pre><p><strong>一个 HTTP 响应示例</strong>：</p><pre><code class="language-text">HTTP/1.1 200 OK
X-Powered-By: Express
Accept-Ranges: bytes
Cache-Control: public, max-age=0
Last-Modified: Sat, 07 Mar 2020 03:52:30 GMT
ETag: W/"253e-170b31f7de7"
Content-Type: application/javascript; charset=UTF-8
Vary: Accept-Encoding
Content-Encoding: gzip
Date: Fri, 15 May 2020 05:38:05 GMT
Connection: keep-alive
Transfer-Encoding: chunked</code></pre><h3 id="-">方法</h3><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-1eff029d1e35612fb85ad1d6765d50c4_720w.jpg" class="kg-image" alt="v2-1eff029d1e35612fb85ad1d6765d50c4_720w" width="600" height="400" loading="lazy"></figure><h3 id="get-head">GET 和 HEAD</h3><p>其中 GET 和 HEAD 被称为安全方法，因为它们是幂等的（如果一个请求不管执行多少次，其结果都是一样的，这个请求就是<strong>幂等的</strong>），类似于 POST 就不是幂等的。</p><p>HEAD 方法和 GET 方法很类似，但服务器在响应中只返回首部。这就允许客户端在未获取实际资源的情况下，对资源的首部进行检查。使用 HEAD，可以：</p><ol><li>在不获取资源的情况下了解资源的情况。</li><li>通过查看响应状态码，看看某个对象是否存在。</li><li>通过查看首部，了解测试资源是否被修改了。</li></ol><p>服务器开发者必须确保返回的首部与 GET 请求所返回的首部完全相同。遵循 HTTP/1.1 规范，就必须实现 HEAD 方法。</p><h3 id="put">PUT</h3><p>与 GET 方法从服务器读取文档相反，PUT 方法会向服务器写入文档。PUT 方法的语义就是让服务器用请求的主体部分来创建一个由所请求的 URL 命名的新文档。 如果那个文档已存在，就覆盖它。</p><h3 id="post">POST</h3><p>POST 方法通常用来向服务器发送表单数据。</p><h3 id="trace">TRACE</h3><p>客户端发起一个请求时，这个请求可能要穿过路由器、防火墙、代理、网关等。每个中间节点都可能会修改原始的 HTTP 请求，TRACE 方法允许客户端在最终发起请求时，看看它变成了什么样子。</p><p>TRACE 请求会在目的服务器端发起一个“环回”诊断。行程最后一站的服务器会弹回一条 TRACE 响应，并在响应主体中携带它收到的原始请求报文。 这样客户端就可以查看在所有中间 HTTP 应用程序组成的请求/响应链上，原始报文是否被毁坏或修改过。<br></p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-f66c499fa15d2ae881c5aec8d3ee70be_720w.jpg" class="kg-image" alt="v2-f66c499fa15d2ae881c5aec8d3ee70be_720w" width="600" height="400" loading="lazy"></figure><p>TRACE 方法主要用于诊断，用于验证请求是否如愿穿过了请求/响应链。它也是一种工具，用来查看代理和其他应用程序对用户请求所产生的效果。 TRACE 请求中不能带有实体的主体部分。TRACE 响应的实体主体部分包含了响应服务器收到的请求的精确副本。</p><h3 id="options">OPTIONS</h3><p>OPTIONS 方法请求 Web 服务器告知其支持的各种功能。</p><h3 id="delete">DELETE</h3><p>DELETE 方法就是让服务器删除请求 URL 所指定的资源。</p><h3 id="--1">状态码</h3><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-aff02263117f428811e86b71ad01ec7a_720w.jpg" class="kg-image" alt="v2-aff02263117f428811e86b71ad01ec7a_720w" width="600" height="400" loading="lazy"></figure><h3 id="300-399-">300~399 重定向状态码</h3><p>重定向状态码要么告诉客户端使用替代位置来访问他们感兴趣的资源，要么提供一个替代的响应而不是资源的内容。 如果资源已被移动，可以发送一个重定向状态码和一个可选的 Location 首部来告知客户端资源已被移走，以及现在在哪里可以找到它。这样，浏览器可以在不打扰使用者的情况下，透明地转入新的位置。</p><h3 id="400-499-">400~499 客户端错误状态码</h3><p>有时客户端会发送一些服务器无法处理的东西，例如格式错误的请求报文、一个不存在的 URL。</p><h3 id="500-599-">500~599 服务器错误状态码</h3><p>有时客户端发送了一条有效请求，服务器自身却出错了。</p><h3 id="--2">首部</h3><p>首部和方法共同配合工作，决定了客户端和服务器能做什么事情。</p><p><strong>首部分类</strong>：</p><ol><li>通用首部，可以出现在请求或响应报文中。</li><li>请求首部，提供更多有关请求的信息。</li><li>响应首部，提供更多有关响应的信息。</li><li>实体首部，描述主体的长度和内容，或者资源自身。</li><li>扩展首部，规范中没有定义的新首部。</li></ol><h3 id="--3">通用首部</h3><p>有些首部提供了与报文相关的最基本信息，它们被称为通用首部。以下是一些常见的通用首部：<br></p><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-2f7b70e0538ccfed82cb4bea696b5f79_720w.jpg" class="kg-image" alt="v2-2f7b70e0538ccfed82cb4bea696b5f79_720w" width="600" height="400" loading="lazy"></figure><h3 id="--4"><br>请求首部</h3><p>请求首部是只在请求报文中有意义的首部，用于说明请求的详情。以下是一些常见的请求首部：</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-bd43f3dbc08e9df61b77041526831854_720w.jpg" class="kg-image" alt="v2-bd43f3dbc08e9df61b77041526831854_720w" width="600" height="400" loading="lazy"></figure><h3 id="--5">响应首部</h3><p>响应首部让服务器为客户端提供了一些额外的信息。</p><h3 id="--6">实体首部</h3><p>实体首部提供了有关实体及其内容的大量信息，从有关对象类型的信息，到能够对资源使用的各种有效的请求方法。</p><p>例如<strong>内容首部</strong>，提供了与实体内容有关的特定信息，说明了其类型、尺寸以及处理它所需的其他有用信息。 另外，通用的缓存首部说明了如何或什么时候进行缓存。<strong>实体的缓存首部</strong>提供了与被缓存实体有关的信息。</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-97b2ecf5532a21f520742cc0edb2f634_720w.jpg" class="kg-image" alt="v2-97b2ecf5532a21f520742cc0edb2f634_720w" width="600" height="400" loading="lazy"></figure><h3 id="--7">性能优化</h3><h3 id="1-http-">1. 减少 HTTP 请求</h3><p>每发起一个 HTTP 请求，都得经历三次握手建立 TCP 连接，如果连接只用来交换少量数据，这个过程就会严重降低 HTTP 性能。所以我们可以将多个小文件合成一个大文件，从而减少 HTTP 请求次数。</p><p>其实由于持久连接（重用 TCP 连接，以消除连接及关闭时延；HTTP/1.1 默认开启持久连接）的存在，每个新请求不一定都需要建立一个新的 TCP 连接。但是，浏览器处理完一个 HTTP 请求才能发起下一个，所以在 TCP 连接数没达到浏览器规定的上限时，还是会建立新的 TCP 连接。从这点来看，减少 HTTP 请求仍然是有必要的。</p><h3 id="2-cdn">2. 静态资源使用 CDN</h3><p>内容分发网络（CDN）是一组分布在多个不同地理位置的 Web 服务器。我们都知道，当服务器离用户越远时，延迟越高。CDN 就是为了解决这一问题，在多个位置部署服务器，让用户离服务器更近，从而缩短请求时间。</p><h3 id="3-">3. 善用缓存</h3><p>为了避免用户每次访问网站都得请求文件，我们可以通过添加 Expires 头来控制这一行为。Expires 设置了一个时间，只要在这个时间之前，浏览器都不会请求文件，而是直接使用缓存。</p><p>不过这样会产生一个问题，当文件更新了怎么办？怎么通知浏览器重新请求文件？</p><p>可以通过更新页面中引用的资源链接地址，让浏览器主动放弃缓存，加载新资源。</p><p>具体做法是把资源地址 URL 的修改与文件内容关联起来，也就是说，只有文件内容变化，才会导致相应 URL 的变更，从而实现文件级别的精确缓存控制。什么东西与文件内容相关呢？我们会很自然的联想到利用<a href="https://link.zhihu.com/?target=https%3A//baike.baidu.com/item/%25E6%25B6%2588%25E6%2581%25AF%25E6%2591%2598%25E8%25A6%2581%25E7%25AE%2597%25E6%25B3%2595/3286770%3Ffromtitle%3D%25E6%2591%2598%25E8%25A6%2581%25E7%25AE%2597%25E6%25B3%2595%26fromid%3D12011257" rel="nofollow noreferrer">数据摘要要算法</a>对文件求摘要信息，摘要信息与文件内容一一对应，就有了一种可以精确到单个文件粒度的缓存控制依据了。</p><p>参考资料：</p><ul><li><a href="https://www.zhihu.com/question/20790576/answer/32602154">张云龙--大公司里怎样开发和部署前端代码？</a></li></ul><h3 id="4-">4. 压缩文件</h3><p>压缩文件可以减少文件下载时间，让用户体验性更好。</p><p>gzip 是目前最流行和最有效的压缩方法。可以通过向 HTTP 请求头中的 Accept-Encoding 头添加 gzip 标识来开启这一功能。当然，服务器也得支持这一功能。</p><p>举个例子，我用 Vue 开发的项目构建后生成的 app.js 文件大小为 1.4MB，使用 gzip 压缩后只有 573KB，体积减少了将近 60%。</p><h3 id="5-max-age-no-cache-">5. 通过 max-age 和 no-cache 实现文件精确缓存</h3><p>通用消息头部 <code>Cache-Control</code> 其中有两个选项：</p><ol><li><code>max-age</code>: 设置缓存存储的最大周期，超过这个时间缓存被认为过期(单位秒)。在这个时间前，浏览器读取文件不会发出新请求，而是直接使用缓存。</li><li><code>no-cache</code>: 指定 no-cache 表示客户端可以缓存资源，每次使用缓存资源前都必须重新验证其有效性。</li></ol><p>我们可以将那些长期不变的静态资源设置一个非常长的缓存时间，例如设置成缓存一年。</p><p>然后将 <code>index.html</code> 文件设置成 <code>no-cache</code>。这样每次访问网站时，浏览器都会询问 <code>index.html</code> 是否有更新，如果没有，就使用旧的 <code>index.html</code> 文件。如果有更新，就读取新的 <code>index.html</code> 文件。当加载新的 <code>index.html</code> 时，也会去加载里面新的 URL 资源。</p><p>例如 <code>index.html</code> 原来引用了 <code>a.js</code> 和 <code>b.js</code>，现在更新了变成 <code>a.js</code> 和 <code>c.js</code>。那就只会加载 <code>c.js</code> 文件。</p><p>具体请看 <a href="https://link.zhihu.com/?target=https%3A//github.com/woai3c/node-blog/blob/master/doc/node-blog7.md" rel="nofollow noreferrer">webpack + express 实现文件精确缓存</a>。</p><h2 id="https">HTTPS</h2><p>HTTPS 是最流行的 HTTP 安全形式，由网景公司首创，所有主要的浏览器和服务器都支持此协议。 使用 HTTPS 时，所有的 HTTP 请求和响应数据在发送之前，都要进行加密。加密可以使用 SSL 或 TLS。</p><figure class="kg-card kg-image-card"><img src="https://pic4.zhimg.com/80/v2-bb65d4c1c08bffc3a1e10968e18911f7_720w.jpg" class="kg-image" alt="v2-bb65d4c1c08bffc3a1e10968e18911f7_720w" width="600" height="400" loading="lazy"></figure><p>SSL/TLS 协议作用在 HTTP 协议之下，对于上层应用来说，原来的发送/接收数据流程不变，这就很好地兼容了老的 HTTP 协议。由于 SSL/TLS 差别不大，下面统一使用 SSL。</p><p>要想了解 HTTPS 为何安全，还得继续了解一下这些概念：<strong>加密算法</strong>、<strong>摘要算法</strong>、<strong>数字签名</strong>和<strong>数字证书</strong>。</p><h3 id="--8">加密算法</h3><h3 id="--9">对称密钥密码体制</h3><p>对称密钥密码体制，即加密密钥和解密密钥是使用相同的密码体制。对称密钥加密技术的缺点之一就是发送者和接收者在对话之前，一定要有一个共享的密钥，所以不太安全。</p><h3 id="--10">公钥密码体制</h3><p>公钥密码体制使用不同的加密密钥与解密密钥。公钥密码体制产生的主要原因有两个：一是对称密钥密码体制的密钥分配问题，二是对数字签名的需求。</p><p>在公钥密码体制中，加密密钥是公开的，解密密钥是需要保密的，加密算法和解密算法也是公开的。</p><p>公钥密码体制的加密和解密有如下特点：</p><ol><li><strong>密钥对产生器</strong>产生出接收者 B 的一对密钥，即加密密钥 PK 和解密密钥 SK。</li><li>发送者 A 用 B 的公钥 PK 作为加密密钥来加密信息，B 接收后用解密密钥 SK 解密。</li></ol><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-5ad7018640fb80e50e92d20484e81f86_720w.jpg" class="kg-image" alt="v2-5ad7018640fb80e50e92d20484e81f86_720w" width="600" height="400" loading="lazy"></figure><p>使用对称密钥时，由于双方使用同样的密钥，因此在通信信道上可以进行一对一的双向保密通信，双方都可以用同一个密钥加密解密。</p><p>使用公开密钥时，在通信信道上可以是多对一的单向保密信道。即可以有多人持有 B 的公钥，但只有 B 才能解密。</p><h3 id="--11">摘要算法</h3><p>摘要算法的主要特征是加密过程不需要密钥，并且经过加密的数据无法被解密，目前可以被解密逆向的只有CRC32算法，只有输入相同的明文数据经过相同的消息摘要算法才能得到相同的密文。</p><h3 id="--12">数字签名</h3><p>用加密系统对报文进行签名，以说明是谁编写的报文，同时证明报文未被篡改过，这种技术称为<strong>数字签名</strong>。</p><p>数字签名是附加在报文上的特殊加密校验码。使用数字签名的好处有：</p><ol><li>签名可以证明是作者编写了这条报文。只有作者才会有最机密的私有密钥，因此，只有作者才能计算出这些校验和。</li><li>签名可以防止报文被篡改，如果有人在报文传输过程中对其进行了修改，校验和就不再匹配了。</li></ol><p>数字签名通常是用非对称公开密钥技术产生的。</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-dbe067a589d86e584a226ddd31c49f80_720w.jpg" class="kg-image" alt="v2-dbe067a589d86e584a226ddd31c49f80_720w" width="600" height="400" loading="lazy"></figure><p>看上图，任何人都能用 A 的公钥 PK 对密文进行 E 运算后得到 A 发送的明文。可见这种通信并非为了保密，而是为了进行签名和核实签名，即确认此信息是 A 发送的（使用 A 的密钥进行加密的报文，只有使用 A 的公钥才能正确解密）。 但上述过程仅对报文进行了签名，对报文 X 本身却未保密，所以要采用下图的方法，同时实现秘密通信和数字签名。</p><figure class="kg-card kg-image-card"><img src="https://pic4.zhimg.com/80/v2-113d720a3ca11d8d18ead0a54ac00e43_720w.jpg" class="kg-image" alt="v2-113d720a3ca11d8d18ead0a54ac00e43_720w" width="600" height="400" loading="lazy"></figure><h3 id="--13">数字证书</h3><p>假如你想访问一个网站，怎么确保对方给你的公钥是你想访问的网站的公钥，而不是被中间人篡改过的？</p><p>数字证书的出现就是为了解决这个问题，它是由数字证书认证机构颁发的，用来证明公钥拥有者的身份。换句话说，数字证书的作用就相当于人的身份证，身份证证明了张三就是张三，而不是别人。</p><p><strong>数字证书一般包含以下内容</strong>：</p><ol><li>对象的名称（人、服务器、组织等）；</li><li>过期时间；</li><li>证书发布者（由谁为证书担保）；</li><li>来自证书发布者的数字签名；</li><li>对象的公钥；</li><li>对象和所用签名算法的描述性信息。</li></ol><p>任何人都可以创建一个数字证书，但由谁来担保才是重点。</p><p><strong>数字证书的数字签名计算过程</strong>：</p><ol><li>用摘要算法对数字证书的内容计算出摘要；</li><li>用数字证书的私钥对摘要进行加密得到数字签名。</li></ol><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-17ec75ef0f9ff1892eb6aada2c3d44e9_720w.jpg" class="kg-image" alt="v2-17ec75ef0f9ff1892eb6aada2c3d44e9_720w" width="600" height="400" loading="lazy"></figure><p>当浏览器收到证书时，会对签名颁发机构进行验证，如果颁发机构是个很有权威的公共签名机构，浏览器可能就知道其公开密钥了（浏览器会预装很多签名颁发机构的证书）。如果对签名颁发机构一无所知，浏览器通常会向用户显示一个对话框，看看他是否相信这个签名发布者。</p><p>因为数字证书的公钥是公开的，任何人都可以用公钥解密出数字证书的数字签名的摘要，然后再用同样的摘要算法对证书内容进行摘要计算，将得出的摘要和解密后的摘要作对比，如果内容一致则说明这个证书没有被篡改过，可以信任。</p><p>这个过程是建立在被大家所认可的证书机构之上得到的公钥，所以这是一种安全的方式。</p><figure class="kg-card kg-image-card"><img src="https://pic1.zhimg.com/80/v2-be99bd75b57e167a6dd28534c6070574_720w.jpg" class="kg-image" alt="v2-be99bd75b57e167a6dd28534c6070574_720w" width="600" height="400" loading="lazy"></figure><h3 id="https-">HTTPS 连接建立过程</h3><p>HTTPS 连接建立过程和 HTTP 差不多，区别在于 HTTP（默认端口 80） 请求只要在 TCP 连接建立后就可以发起，而 HTTPS（默认端口 443） 在 TCP 连接建立后，还需要经历 SSL 协议握手，成功后才能发起请求。</p><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-ee3edd71c7aa0e6434f271aa71852335_720w.jpg" class="kg-image" alt="v2-ee3edd71c7aa0e6434f271aa71852335_720w" width="600" height="400" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-0adc50b67e0be922b2a9d6de861f1c95_720w.jpg" class="kg-image" alt="v2-0adc50b67e0be922b2a9d6de861f1c95_720w" width="600" height="400" loading="lazy"></figure><p>我知道肯定会有人不满足于简化版的 SSL 握手过程，所以我找了一篇文章<a href="https://link.zhihu.com/?target=https%3A//www.jianshu.com/p/7158568e4867" rel="nofollow noreferrer">SSL/TLS 握手过程详解</a>，这篇文章非常详细的讲解了 SSL 握手的每一步骤。建议有兴趣的同学看一看。</p><h2 id="http-2">HTTP/2</h2><p>HTTP/2 是 HTTP/1.x 的扩展，而非替代。所以 HTTP 的语义不变，提供的功能不变，HTTP 方法、状态码、URL 和首部字段等这些核心概念也不变。</p><p>之所以要递增一个大版本到 2.0，主要是因为它改变了客户端与服务器之间交换数据的方式。HTTP 2.0 增加了新的二进制分帧数据层，而这一层并不兼容之前的 HTTP 1.x 服务器及客户端——是谓 2.0。</p><h3 id="http-2-">HTTP/2 连接建立过程</h3><p>现在的主流浏览器 HTTP/2 的实现都是基于 SSL/TLS 的，也就是说使用 HTTP/2 的网站都是 HTTPS 协议的，所以本文只讨论基于 SSL/TLS 的 HTTP/2 连接建立过程。</p><p>基于 SSL/TLS 的 HTTP/2 连接建立过程和 HTTPS 差不多。在 SSL/TLS 握手协商过程中，客户端在 ClientHello 消息中设置 ALPN（应用层协议协商）扩展来表明期望使用 HTTP/2 协议，服务器用同样的方式回复。通过这种方式，HTTP/2 在 SSL/TLS 握手协商过程中就建立起来了。</p><h3 id="http-1-1-">HTTP/1.1 的问题</h3><h3 id="1-">1. 队头阻塞</h3><p>在 HTTP 请求应答过程中，如果出现了某种情况，导致响应一直未能完成，那后面所有的请求就会一直阻塞着，这种情况叫队头阻塞。</p><h3 id="2-tcp-">2. 低效的 TCP 利用</h3><p>由于 <a href="https://link.zhihu.com/?target=https%3A//baike.baidu.com/item/%25E6%2585%25A2%25E5%2590%25AF%25E5%258A%25A8/8242395" rel="nofollow noreferrer">TCP 慢启动机制</a>，导致每个 TCP 连接在一开始的时候传输速率都不高，在处理多个请求后，才会慢慢达到“合适”的速率。对于请求数据量很小的 HTTP 请求来说，这种情况就是种灾难。</p><h3 id="3--1">3. 臃肿的消息首部</h3><p>HTTP/1.1 的首部无法压缩，再加上 cookie 的存在，经常会出现首部大小比请求数据大小还大的情况。</p><h3 id="4--1">4. 受限的优先级设置</h3><p>HTTP/1.1 无法为重要的资源指定优先级，每个 HTTP 请求都是一视同仁。</p><p>在继续讨论 HTTP/2 的新功能之前，先把 HTTP/1.1 的问题列出来是有意义的。因为 HTTP/2 的某些新功能就是为了解决上述某些问题而产生的。</p><h3 id="--14">二进制分帧层</h3><p>HTTP/2 是基于帧的协议。采用分帧是为了将重要信息封装起来，让协议的解析方可以轻松阅读、解析并还原信息。</p><p>而 HTTP/1.1 是以文本分隔的。解析 HTTP/1.1 不需要什么高科技，但往往速度慢且容易出错。你需要不断地读入字节，直到遇到分隔符 CRLF 为止，同时还要考虑不守规矩的客户端，它只会发送 LF。</p><p>解析 HTTP/1.1 的请求或响应还会遇到以下问题：</p><ol><li>一次只能处理一个请求或响应，完成之前不能停止解析。</li><li>无法预判解析需要多少内存。</li></ol><p>HTTP/2 有了帧，处理协议的程序就能预先知道会收到什么，并且 HTTP/2 有表示帧长度的字段。</p><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-b5e21a1d51a86e69835cf4fc2b0ead6d_720w.jpg" class="kg-image" alt="v2-b5e21a1d51a86e69835cf4fc2b0ead6d_720w" width="600" height="400" loading="lazy"></figure><h3 id="--15">帧结构</h3><pre><code class="language-text">+-----------------------------------------------+
 |                 Length (24)                   |
 +---------------+---------------+---------------+
 |   Type (8)    |   Flags (8)   |
 +-+-------------+---------------+-------------------------------+
 |R|                 Stream Identifier (31)                      |
 +=+=============================================================+
 |                   Frame Payload (0...)                      ...
 +---------------------------------------------------------------+</code></pre><figure class="kg-card kg-image-card"><img src="https://pic4.zhimg.com/80/v2-7f7d60db1b3a2d3ff25b613a4cbeaa97_720w.jpg" class="kg-image" alt="v2-7f7d60db1b3a2d3ff25b613a4cbeaa97_720w" width="600" height="400" loading="lazy"></figure><p>由于 HTTP/2 是分帧的，请求和响应都可以多路复用，有助于解决类似类似队头阻塞的问题。</p><h3 id="--16">帧类型</h3><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-de35fa232ac8c4b181ede6f7af13925d_720w.jpg" class="kg-image" alt="v2-de35fa232ac8c4b181ede6f7af13925d_720w" width="600" height="400" loading="lazy"></figure><h3 id="--17">多路复用</h3><p>在 HTTP/1.1 中，如果客户端想发送多个并行的请求，那么必须使用多个 TCP 连接。</p><p>而 HTTP/2 的二进制分帧层突破了这一限制，所有的请求和响应都在同一个 TCP 连接上发送：客户端和服务器把 HTTP 消息分解成多个帧，然后乱序发送，最后在另一端再根据流 ID 重新组合起来。</p><p>这个机制为 HTTP 带来了巨大的性能提升，因为：</p><ul><li>可以并行交错地发送请求，请求之间互不影响；</li><li>可以并行交错地发送响应，响应之间互不干扰；</li><li>只使用一个连接即可并行发送多个请求和响应；</li><li>消除不必要的延迟，从而减少页面加载的时间；</li><li>不必再为绕过 HTTP 1.x 限制而多做很多工作；</li></ul><figure class="kg-card kg-image-card"><img src="https://pic2.zhimg.com/80/v2-369330c2d4712cb12cdb7124ec691931_720w.jpg" class="kg-image" alt="v2-369330c2d4712cb12cdb7124ec691931_720w" width="600" height="400" loading="lazy"></figure><h3 id="--18">流</h3><p>HTTP/2 规范对流的定义是：HTTP/2 连接上独立的、双向的帧序列交换。如果客户端想要发出请求，它会开启一个新流，然后服务器在这个流上回复。 由于有分帧，所以多个请求和响应可以交错，而不会互相阻塞。流 ID 用来标识帧所属的流。</p><p>客户端到服务器的 HTTP/2 连接建立后，通过发送 HEADERS 帧来启动新的流。如果首部需要跨多个帧，可能还会发送 CONTINUATION 帧。该 HEADERS 帧可能来自请求或响应。 后续流启动的时候，会发送一个带有递增流 ID 的新 HEADERS 帧。</p><h3 id="--19">消息</h3><p>HTTP 消息泛指 HTTP 请求或响应，消息由一或多个帧组成，这些帧可以乱序发送，然后再根据每个帧首部的流 ID 重新组装。</p><p>一个消息至少由 HEADERS 帧（它初始化流）组成，并且可以另外包含 CONTINUATION 和 DATA 帧，以及其他的 HEADERS 帧。</p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-b42c13b2eb2f9e68fa6c525b0c2ec1ba_720w.jpg" class="kg-image" alt="v2-b42c13b2eb2f9e68fa6c525b0c2ec1ba_720w" width="600" height="400" loading="lazy"></figure><p>HTTP/1.1 的请求和响应部分都分成消息首部和消息体两部分；HTTP/2 的请求和响应分成 HEADERS 帧和 DATA 帧。</p><h3 id="--20">优先级</h3><p>把 HTTP 消息分解为很多独立的帧之后，就可以通过优化这些帧的交错和传输顺序，进一步提升性能。</p><p>通过 HEADERS 帧和 PRIORITY 帧，客户端可以明确地和服务器沟通它需要什么，以及它需要这些资源的顺序。具体来讲，服务器可以根据流的优先级，控制资源分配（CPU、内存、带宽），而在响应数据准备好之后，优先将最高优先级的帧发送给客户端。</p><h3 id="--21">流量控制</h3><p>在同一个 TCP 连接上传输多个数据流，就意味着要共享带宽。标定数据流的优先级有助于按序交付，但只有优先级还不足以确定多个数据流或多个连接间的资源分配。</p><p>为解决这个问题，HTTP/2 为数据流和连接的流量控制提供了一个简单的机制：</p><ul><li>流量控制基于每一跳进行，而非端到端的控制；</li><li>流量控制基于 WINDOW_UPDATE 帧进行，即接收方广播自己准备接收某个数据流的多少字节，以及对整个连接要接收多少字节；</li><li>流量控制窗口大小通过 WINDOW_UPDATE 帧更新，这个字段指定了流 ID 和窗口大小递增值；</li><li>流量控制有方向性，即接收方可能根据自己的情况为每个流乃至整个连接设置任意窗口大小；</li><li>流量控制可以由接收方禁用，包括针对个别的流和针对整个连接。</li></ul><p>HTTP/2 连接建立之后，客户端与服务器交换 SETTINGS 帧，目的是设置双向的流量控制窗口大小。除此之外，任何一端都可以选择禁用个别流或整个连接的流量控制。</p><h3 id="--22">服务器推送</h3><p>HTTP/2 新增的一个强大的新功能，就是服务器可以对一个客户端请求发送多个响应。换句话说，除了对最初请求的响应外，服务器还可以额外向客户端推送资源，而无需客户端明确地请求。</p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-d4e4f7bbaa1d8d2707951dfa993291e2_720w.jpg" class="kg-image" alt="v2-d4e4f7bbaa1d8d2707951dfa993291e2_720w" width="600" height="400" loading="lazy"></figure><p>为什么需要这样一个机制呢？通常的 Web 应用都由几十个资源组成，客户端需要分析服务器提供的文档才能逐个找到它们。那为什么不让服务器提前就把这些资源推送给客户端，从而减少额外的时间延迟呢？服务器已经知道客户端下一步要请求什么资源了，这时候服务器推送即可派上用场。</p><p>另外，客户端也可以拒绝服务器的推送。</p><h3 id="--23">首部压缩</h3><p>HTTP/1.1 存在的一个问题就是臃肿的首部，HTTP/2 对这一问题进行了改进，可以对首部进行压缩。 在一个 Web 页面中，一般都会包含大量的请求，而其中有很多请求的首部往往有很多重复的部分。</p><p>例如有如下两个请求：</p><pre><code class="language-text">:authority: unpkg.zhimg.com
:method: GET
:path: /za-js-sdk@2.16.0/dist/zap.js
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: zh-CN,zh;q=0.9
cache-control: no-cache
pragma: no-cache
referer: https://www.zhihu.com/
sec-fetch-dest: script
sec-fetch-mode: no-cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36</code></pre><pre><code class="language-http">:authority: zz.bdstatic.com
:method: GET
:path: /linksubmit/push.js
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: zh-CN,zh;q=0.9
cache-control: no-cache
pragma: no-cache
referer: https://www.zhihu.com/
sec-fetch-dest: script
sec-fetch-mode: no-cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36</code></pre><p>从上面两个请求可以看出来，有很多数据都是重复的。如果可以把相同的首部存储起来，仅发送它们之间不同的部分，就可以节省不少的流量，加快请求的时间。</p><p>HTTP/2 在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键－值对，对于相同的数据，不再通过每次请求和响应发送。</p><p>下面再来看一个简化的例子，假设客户端按顺序发送如下请求首部：</p><pre><code class="language-text">Header1:foo
Header2:bar
Header3:bat</code></pre><p>当客户端发送请求时，它会根据首部值创建一张表：</p><figure class="kg-card kg-image-card"><img src="https://pic3.zhimg.com/80/v2-50b11e7a83b07c281fcfb483c576f542_720w.jpg" class="kg-image" alt="v2-50b11e7a83b07c281fcfb483c576f542_720w" width="600" height="400" loading="lazy"></figure><p>如果服务器收到了请求，它会照样创建一张表。 当客户端发送下一个请求的时候，如果首部相同，它可以直接发送这样的首部块：</p><pre><code class="language-text">62 63 64</code></pre><p>服务器会查找先前建立的表格，并把这些数字还原成索引对应的完整首部。</p><h3 id="--24">性能优化</h3><p>使用 HTTP/2 代替 HTTP/1.1，本身就是一种巨大的性能提升。 这小节要聊的是在 HTTP/1.1 中的某些优化手段，在 HTTP/2 中是不必要的，可以取消的。</p><h3 id="--25">取消合并资源</h3><p>在 HTTP/1.1 中要把多个小资源合并成一个大资源，从而减少请求。而在 HTTP/2 就不需要了，因为 HTTP/2 所有的请求都可以在一个 TCP 连接发送。</p><h3 id="--26">取消域名拆分</h3><p>取消域名拆分的理由同上，再多的 HTTP 请求都可以在一个 TCP 连接上发送，所以不需要采取多个域名来突破浏览器 TCP 连接数限制这一规则了。</p><h2 id="--27">参考资料</h2><ul><li><a href="https://link.zhihu.com/?target=https%3A//book.douban.com/subject/10746113/" rel="nofollow noreferrer">HTTP权威指南</a></li><li><a href="https://link.zhihu.com/?target=https%3A//book.douban.com/subject/27665112/" rel="nofollow noreferrer">HTTP/2基础教程</a></li><li><a href="https://link.zhihu.com/?target=https%3A//www.jianshu.com/p/7158568e4867" rel="nofollow noreferrer">SSL/TLS 握手过程详解</a></li><li><a href="https://link.zhihu.com/?target=https%3A//www.jianshu.com/p/ffe8c203a471" rel="nofollow noreferrer">互联网安全之数字签名、数字证书与PKI系统</a></li><li><a href="https://link.zhihu.com/?target=https%3A//book.douban.com/subject/26960678/" rel="nofollow noreferrer">计算机网络（第7版）</a></li><li><a href="https://link.zhihu.com/?target=https%3A//book.douban.com/subject/25856314/" rel="nofollow noreferrer">Web性能权威指南</a></li></ul><h3 id="--28"><a href="https://www.zhihu.com/people/tan-guang-zhi-19/posts">更多文章，敬请关注</a></h3> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 用 JavaScript 发起 HTTP 请求的几种方法 ]]>
                </title>
                <description>
                    <![CDATA[ JavaScript 具有非常棒的模块和方法，可以用来建立可从服务器端资源发送或接收数据的 HTTP 请求。本文会带着大家一起看看在 JavaScript 中常用的建立 HTTP 请求的方式有哪些。 Ajax Ajax 是最常规的建立异步 HTTP 请求的方式。你可以使用 HTTP POST 方法来发送数据，以及使用 HTTP GET 来接收数据。我们先来看看如何发起一个GET 请求。这里我会用到一个免费在线的 REST API 工具 JSONPlaceholder，它可以用来给开发者返回随机的 JSON 格式数据。 要在 Ajax 中发起一个 HTTP 调用，你需要初始化一个新的 XMLHttpRequest() 方法，指定 URL 端点和 HTTP 方法（在本例中为 GET）。最后，使用open() 方法将两者结合起来，并调用send() 方法执行请求。 我们可以在XMLHTTPRequest.onreadystatechange 的事件监听器中输出 HTTP 请求结果日志到控制台中，这个事件监听器会在 readystatechanged 事件发生的时候触发。 const  ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/the-most-popular-ways-to-make-an-http-request-in-javascript/</link>
                <guid isPermaLink="false">5fe2fec839641a0517d52589</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTTP ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Ajax ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ arronKler ]]>
                </dc:creator>
                <pubDate>Tue, 23 Mar 2021 09:35:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2020/12/1_gqHgCNubMncv7EwWNdArGQ.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>JavaScript 具有非常棒的模块和方法，可以用来建立可从服务器端资源发送或接收数据的 HTTP 请求。本文会带着大家一起看看在 JavaScript 中常用的建立 HTTP 请求的方式有哪些。</p><h3 id="ajax">Ajax</h3><p>Ajax 是最常规的建立异步 HTTP 请求的方式。你可以使用 HTTP POST 方法来发送数据，以及使用 HTTP GET 来接收数据。我们先来看看如何发起一个 &nbsp;<code>GET</code> &nbsp;请求。这里我会用到一个免费在线的 REST API 工具 JSONPlaceholder，它可以用来给开发者返回随机的 JSON 格式数据。</p><p>要在 Ajax 中发起一个 HTTP 调用，你需要初始化一个新的 <code>XMLHttpRequest()</code> 方法，指定 URL 端点和 HTTP 方法（在本例中为 GET）。最后，使用 &nbsp;<code>open()</code> &nbsp;方法将两者结合起来，并调用 &nbsp;<code>send()</code> &nbsp;方法执行请求。</p><p>我们可以在 &nbsp;<code>XMLHTTPRequest.onreadystatechange</code> &nbsp;的事件监听器中输出 HTTP 请求结果日志到控制台中，这个事件监听器会在 &nbsp;<code>readystatechanged</code> &nbsp;事件发生的时候触发。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-28.png" class="kg-image" alt="image-28" width="600" height="400" loading="lazy"></figure><pre><code class="language-js">const Http = new XMLHttpRequest();
const url='https://jsonplaceholder.typicode.com/posts';
Http.open("GET", url);
Http.send();

Http.onreadystatechange = (e) =&gt; {
  console.log(Http.responseText)
}
</code></pre><p>如果你查看浏览器的控制台，上面的代码会返回一组 JSON 格式的数组数据。但是我们怎么知道请求已经完成了呢？换句话说，我们应该怎样处理 Ajax 的响应数据呢？</p><p><code>onreadystatechange</code> &nbsp;有两个方式可以让我们可以检测到当前请求的状态， &nbsp;<code>readyState</code> &nbsp;和 &nbsp;<code>status</code>。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-29.png" class="kg-image" alt="image-29" width="600" height="400" loading="lazy"></figure><p>如果 &nbsp;<code>readyState</code> &nbsp;等于 4，意味着请求已经完成了。<code>readyState</code> &nbsp;这个属性可以有 5 种状态值。你可以点击这里<a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState">了解更多</a>。</p><p>除了直接通过 JavaScript 创建 Ajax 调用，还有其他的非常有效的创建 HTTP 调用的方法，比如 jQuery 中的方法 &nbsp;<code>$.Ajax</code>。现在我们就来讨论这些方法。</p><h3 id="jquery-">jQuery 方法</h3><p>jQuery 有很多可以轻松处理 HTTP 请求的方法。为了能使用到这些方法，你需要在你的项目中引入 jQuery 库。</p><pre><code class="language-html">&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"&gt;&lt;/script&gt;
</code></pre><h4 id="-ajax">$.ajax</h4><p>jQuery 的 ajax 是发起 HTTP 调用最简单的方法之一。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-30.png" class="kg-image" alt="image-30" width="600" height="400" loading="lazy"></figure><p>$.ajax 方法拥有很多参数，有的是必要的，有的是可选的。它有两个回调选项 &nbsp;<code>success</code> &nbsp;和 &nbsp;<code>error</code> &nbsp;，可以用来处理接收到的响应数据。</p><h4 id="-get-">$.get 方法</h4><p>$.get 方法用来执行 GET 请求，它接收两个参数：端点和回调函数。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-31.png" class="kg-image" alt="image-31" width="600" height="400" loading="lazy"></figure><h4 id="-post">$.post</h4><p><code>**$.post**</code> &nbsp;方法是另一种向服务端发送数据的方法，它接收三个参数：<code>url</code>，你想要发送的数据，和一个回调函数。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-32.png" class="kg-image" alt="image-32" width="600" height="400" loading="lazy"></figure><h4 id="-getjson">$.getJSON</h4><p><code>$.getJSON</code> &nbsp;方法仅用于获取 JSON 格式的数据。它接收两个参数：<code>url</code> &nbsp;和一个回调函数。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-33.png" class="kg-image" alt="image-33" width="600" height="400" loading="lazy"></figure><p>jQuery 有以上这些方法用来给远端服务器发起请求或者传递数据。不过你最终可以将所有的这些方法都用一个方法来实现: &nbsp;<code>$.ajax</code> &nbsp;, 正如下面示例中所看到的那样。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-34.png" class="kg-image" alt="image-34" width="600" height="400" loading="lazy"></figure><h3 id="fetch">fetch</h3><p><code>fetch</code> &nbsp;是一个功能强大的新的 web API，它能够让你发起异步的请求。实际上， &nbsp;<code>fetch</code> &nbsp;是最好的也是我最喜欢用的发起 HTTP 请求的方式之一。它会返回一个 “Promise”，这也是 ES6 中最强大的特性之一，如果你不是很熟悉 ES6，可以看看<a href="https://medium.freecodecamp.org/write-less-do-more-with-javascript-es6-5fd4a8e50ee2">这篇文章</a>了解一下。Promise 可以让我们用一种更聪明的方式处理异步请求。让我们来看一下 &nbsp;<code>fetch</code> &nbsp;从技术上来说是如何工作的。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-35.png" class="kg-image" alt="image-35" width="600" height="400" loading="lazy"></figure><p><code>fetch</code> &nbsp;函数接收一个必要参数：<code>端点</code> &nbsp;URL。在下面的示例中它也有其它的可选参数：</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-36.png" class="kg-image" alt="image-36" width="600" height="400" loading="lazy"></figure><p>如你所见，<code>fetch</code> &nbsp;在创建 HTTP 请求方面有很多优势。你可以从<a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch">这里</a>了解更多。另外，在 fetch 之上也有一些其他的模块和插件可以让我们给服务端发送请求或者从服务端接收请求，比如<a href="https://github.com/axios/axios">axios</a></p><h3 id="axios">Axios</h3><p>Axios 是一个开源的创建 HTTP 请求的库，它提供了许多好用的特性，让我们来看一看它是如何用的吧。</p><h4 id="usage-">Usage:</h4><p>首先，你需要引入 Axios。这里有两种方式将 Axios 引入你的项目。</p><p>第一种，你可以使用 npm 进行安装:</p><pre><code class="language-shell">npm install axios --save
</code></pre><p>然后你需要引入它:</p><pre><code class="language-js">import axios from 'axios'
</code></pre><p>第二种，你可以使用 CDN 来引入 axios：</p><pre><code class="language-html">&lt;script src="https://unpkg.com/axios/dist/axios.min.js"&gt;&lt;/script&gt;
</code></pre><h4 id="-axios-">使用 axios 创建请求:</h4><p>基于 Axios，你可以使用 &nbsp;<code>GET</code> &nbsp;和 &nbsp;<code>POST</code> &nbsp;来向服务端请求数据和发送数据。</p><h4 id="get-">GET:</h4><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-37.png" class="kg-image" alt="image-37" width="600" height="400" loading="lazy"></figure><p><code>axios</code> 需要一个必填参数，当然你也可以提供第二个可选参数。这个示例调用一些数据作简单的查询。</p><h4 id="post-">POST:</h4><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-38.png" class="kg-image" alt="image-38" width="600" height="400" loading="lazy"></figure><p><a href="https://github.com/axios/axios">Axios</a> &nbsp;返回一个 “Promise”。如果你对 Promise 比较熟悉的话，你应该知道用 Promise 可以用来执行并行请求。这里你就可以用 axios 在同一时间运行多个并行请求。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-39.png" class="kg-image" alt="image-39" width="600" height="400" loading="lazy"></figure><p>Axios 还提供了一些其他的方法和选项，你可以在<a href="https://github.com/axios/axios">这里</a>具体看看。</p><h3 id="angular-httpclient">Angular HttpClient</h3><p>Angular 有它自己的和 Angular 应用一起运行的 HTTP 模块。它使用到了 &nbsp;<a href="http://reactivex.io/rxjs/">RxJS</a> &nbsp;库来处理异步请求，同时还提供了许多用来执行 HTTP 请求的选择。</p><h4 id="-angular-httpclient-">使用 Angular HttpClient 来发起一个服务端调用</h4><p>为了能使用 Angular HttpClient 来发起一个请求，我们需要将代码运行在一个 Angular 应用中。所以我这里就创建了一个。如果你对 Angular 不是很熟悉的话，可以看一下我的文章 &nbsp;<a href="https://medium.freecodecamp.org/learn-how-to-create-your-first-angular-app-in-20-min-146201d9b5a7">20分钟内学会如何创建你的第一个 Angular 应用</a> &nbsp;。</p><p>我们需要做的第一件事儿是在 &nbsp;<code>app.module.ts</code> &nbsp;中引入 &nbsp;<code>HttpClientModule</code> &nbsp;模块。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-40.png" class="kg-image" alt="image-40" width="600" height="400" loading="lazy"></figure><p>然后，我们需要创建一个服务来处理请求。你可以使用 &nbsp;<a href="https://cli.angular.io/">Angular CLI</a> &nbsp;很容易的创建一个服务。</p><pre><code class="language-shell">ng g service  FetchdataService
</code></pre><p>再然后，我们需要在 &nbsp;<code>fetchdataService.ts</code> &nbsp;服务中的引入 HttpClient 并且将其注入到构造器中。</p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-41.png" class="kg-image" alt="image-41" width="600" height="400" loading="lazy"></figure><p>在 &nbsp;<code>app.component.ts</code> &nbsp;文件中引入 &nbsp;<code>fetchdataService</code>。</p><pre><code class="language-ts">//import
import { FetchdataService } from './fetchdata.service';
</code></pre><p>最后，调用这个服务并运行。</p><p><code>app.component.ts:</code></p><figure class="kg-card kg-image-card"><img src="https://chinese.freecodecamp.org/news/content/images/2020/12/image-42.png" class="kg-image" alt="image-42" width="600" height="400" loading="lazy"></figure><p>你可以在 &nbsp;<a href="https://stackblitz.com/edit/angular-httpclinent">Stackblitz</a> &nbsp;上看到这整个示例。</p><h3 id="-">总结</h3><p>我们刚刚了解了在 JavaScript 中最常用的创建 HTTP 请求的几种方式。</p><p>感谢你的阅读。如果你喜欢的话，点击 "关注"，然后可以在 &nbsp;<a href="https://twitter.com/SaidHYN">Twitter</a> &nbsp;上找到我。</p><p>顺便说一下，我最近与一群强大的软件工程师一起为我的一个移动应用程序工作。该组织非常出色，产品交付速度非常快，比我所合作的其他公司和自由职业者要快得多，我认为我可以诚实地推荐他们用于其他项目。如果您想与我联系，请给我<a href="https://chinese.freecodecamp.org/news/the-most-popular-ways-to-make-an-http-request-in-javascript/said@devsdata.com">发送电子邮件</a>。</p><p>原文：<a href="https://www.freecodecamp.org/news/here-is-the-most-popular-ways-to-make-an-http-request-in-javascript-954ce8c95aaa/">Here are the most popular ways to make an HTTP request in JavaScript</a>，作者：<a href="https://www.freecodecamp.org/news/author/saidhayani/">Said Hayani</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 一个不能再普通的函数，如何提供 http 服务？ ]]>
                </title>
                <description>
                    <![CDATA[ 前调：一些吐槽 因为开发过大大大大大大量的 Restful API ，越来越厌烦那种一成不变的代码组织方式。 以 egg为例，要增加一个接口，需要经历繁琐的操作 [路由里注册] ---> [编写 controller] ---> [编写 service]  哪怕我只是想实现一个 a+b => c！ 除此以外，我还调研过某几个比较大的 函数计算 服务商，看看有没有什么好的途径，可以更简便地进行简单接口开发。 让人很失望，天下技术一大抄，它们无一例外都是这样的开发模型： function(event, context, callback) {} 或者 function(event, context) {} 于是你不得不这样写你的代码 // 举例 function(event, context, callback) {   const { a, b } = event.arguments;    ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/way-to-build-restful-api-via-pure-function/</link>
                <guid isPermaLink="false">600a8ecf5f61e30501b5c037</guid>
                
                    <category>
                        <![CDATA[ 函数 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTTP ]]>
                    </category>
                
                    <category>
                        <![CDATA[ API ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ 开发者小蓝 ]]>
                </dc:creator>
                <pubDate>Fri, 22 Jan 2021 09:20:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/01/goran-ivos-TorAcb4AQRc-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <h3 id="">前调：一些吐槽</h3>
<p>因为开发过大大大大大大量的 <code>Restful API</code> ，越来越厌烦那种一成不变的代码组织方式。</p>
<p>以 <code>egg</code>为例，要增加一个接口，需要经历繁琐的操作</p>
<pre><code>[路由里注册] ---&gt; [编写 controller] ---&gt; [编写 service] 
</code></pre>
<h4 id="abc">哪怕我只是想实现一个 <code>a+b =&gt; c</code>！</h4>
<p>除此以外，我还调研过某几个比较大的 <strong>函数计算</strong> 服务商，看看有没有什么好的途径，可以更简便地进行<strong>简单接口开发</strong>。</p>
<p>让人很失望，天下技术一大抄，它们无一例外都是这样的开发模型：</p>
<pre><code>function(event, context, callback) {}
或者
function(event, context) {}
</code></pre>
<p>于是你不得不这样写你的代码</p>
<pre><code>// 举例
function(event, context, callback) {
  const { a, b } = event.arguments; 
  callback(a+b);
}
</code></pre>
<h4 id="">这算个什么鬼函数？！</h4>
<p>你必须改变第一直觉，严格按照厂商的要求来写你的代码，并且寄希望于<strong>有人站出来要求它们统一<code>event</code>、<code>context</code>这些旁系知识的实现细节</strong>。</p>
<h3 id="">并且！</h3>
<p>你很难进行本地测试！</p>
<p>你要构造奇奇怪怪的对象作为参数。哪怕只是测试<strong>两数相加</strong>.</p>
<h5 id="ok">OK! 如果你说，稍微学习一下，其实还是可以用的吧。</h5>
<h4 id="">可以用就是我们的追求吗？要 <strong>应然</strong> 还是 <strong>实然</strong> ？</h4>
<h4 id="">难倒我们期望的样子，不应该是这样吗？</h4>
<pre><code>// 🔥🔥
function (a, b) {
	return a+b;
}
</code></pre>
<h3 id="">正文开始：</h3>
<p>所以，如果我需要实现一个 <code>a+b =&gt; c</code> 的接口，</p>
<p>我期望我的代码是这样的：</p>
<pre><code>export default (a: number, b: number): number =&gt; {
  return a + b;
}
</code></pre>
<p>我期望我的测试是这样的：</p>
<pre><code>describe('sum', () =&gt; {
  it('1+1 is 2', () =&gt; {
    assert.equal(sum(1,1), 2);
  });
});
</code></pre>
<h4 id="">十分明显好吗！</h4>
<p>它并不受制于具体平台实现；</p>
<p>它并不需要你学习其他旁系知识，只关注你的功能本身；</p>
<p>它方便测试，因为它就是一个不能再普通的函数；</p>
<p>它可复用！</p>
<p><img src="https://lanhaooss.oss-cn-shenzhen.aliyuncs.com/images/331/1.png" alt="1" width="606" height="604" loading="lazy"></p>
<h3 id="">多说无益，直接动手</h3>
<pre><code>export default (a: number, b: number): number =&gt; {
  return a + b;
}
</code></pre>
<p>有过<a href="https://chinese.freecodecamp.org/news/practice-in-ast-and-code-gen/">上一篇</a>的基础，我们直奔抽象语法树：</p>
<pre><code>// 由于只有一行代码，结构就简单多了
{
	type: 'ExportDefaultDeclaration',
	declaration: {
		type: 'ArrowFunctionExpression',
		params: [ 下文展开 ],
		body: { 不重要 },
		returnType: { 下文展开 }
	}
}

</code></pre>
<p>我们还是从整体上先看一下，上面这个结构充分表达了源代码的意图：</p>
<ul>
<li>这是一个 <code>export default</code>声明 (<code>ExportDefaultDeclaration </code>)</li>
<li>声明的内容是一个箭头函数 (<code>ArrowFunctionExpression </code>)</li>
</ul>
<p>考虑到，我们希望从这一行代码里面，生成<strong>提供HTTP服务</strong>的基础代码，</p>
<p>那么我们的主要任务就是，从以上有限的信息当中，提取出<strong>Restful API</strong>需要的基础信息：</p>
<ul>
<li>Method</li>
<li>Path</li>
<li>请求参数</li>
</ul>
<h4 id="">🤖 我们一个一个来解决：</h4>
<ol>
<li>
<p>HTTP Method</p>
<p>首选是要确定这个接口，最终通过什么 <code>Method</code>对外服务，在这里源代码并不能提供任何有效信息。</p>
<p><strong>那么我们就默认用 GET 好了</strong></p>
<blockquote>
<p>🔥其他的 Method，会在文末提及</p>
</blockquote>
</li>
<li>
<p>Path， 或者叫 URL</p>
<p>对于一个接口来说，这也是十分关键的信息，这里我们有两种解决方案</p>
<ul>
<li>使用函数名，如果有的话</li>
<li>使用当前文件名</li>
</ul>
<p><strong>我们姑且把 URL 定为  <code>/sum</code> 好了</strong></p>
<blockquote>
<p>🔥 笔者的一个实验性项目里，使用的是文件名</p>
</blockquote>
</li>
<li>
<p>请求参数</p>
<p>如果说前面两点都是基于约定，或者一些简单的手段，</p>
<p>那么在请求参数这个环节，我们必须上价值了，要让 <code>ast</code> 发挥作用！</p>
<p>我们先展开一下上面 <code>ast</code> 里关于函数参数的部分：</p>
<pre><code>// params 部分
[
	{
		name: 'a',
		typeAnnotation: { type: 'TSNumberKeyword' }
	},
	{
		name: 'b',
		typeAnnotation: { type: 'TSNumberKeyword' }
	},
]
</code></pre>
<h4 id="ab">好家伙，可以拿到参数名 <code>a</code> 和 <code>b</code> 了</h4>
<p>结合 <code>TSNumberKeyword</code> 信息，我们甚至能笃定这两个参数是数字类型。</p>
<h4 id="">知道类型，就可以做参数校验！</h4>
<blockquote>
<p>🔥通过原始函数定义的参数类型生成 http 参数校验逻辑，比起手工编写 <code>Joi</code> 配置要可靠得多。</p>
</blockquote>
<h4 id="">等等，还有一个问题没解决</h4>
<p>参数名和参数类型都有了，缺的就是参数位置以及 <code>content-type</code> 。</p>
<p>约定大法好，根据多年开发总结得出：</p>
<p><strong>总所周知， GET 请求的参数就放在 queryString 里吧。</strong></p>
<p><strong>至于 <code>content-type</code> 统一使用 <code>application/json</code> 不接受反驳</strong></p>
</li>
</ol>
<h3 id="">齐活了</h3>
<p>结合上面收集到的信息，我们可以想象最终的场景是：</p>
<ul>
<li>step 1 : 按上面的方式，编写一个不能再普通的函数</li>
<li>step 2: 使用我们编写好的工具，运行这个函数</li>
<li>step 3: 可以通过 <code>http://127.0.0.1:3000/sum?a=11&amp;b=22</code> 来访问这个接口，并且得到结果 33</li>
</ul>
<p><img src="https://lanhaooss.oss-cn-shenzhen.aliyuncs.com/images/331/2.png" alt="2" width="1700" height="1270" loading="lazy"></p>
<p>通过这个截图可知，虽然实现细节比较多，但是<strong>可行性</strong>是没问题的。</p>
<p>并且笔者已经做出了一个实验性项目。</p>
<p>如果对这种模式比较感兴趣，欢迎前来讨论，在这里就不打广告了。</p>
<h3 id="faq">FAQ 环节</h3>
<ul>
<li>
<p>更多的 HTTP_METHOD 怎么办？总不能都用 GET 吧</p>
<blockquote>
<p>目前我选能用的方案是，如果没有声明，就用一个默认的 <code>GET</code>，</p>
</blockquote>
<blockquote>
<p>因为要尽量选一个能覆盖 90% 情况的作为默认值。</p>
</blockquote>
<blockquote>
<p>当我需要使用其他 Method ，我的方案是显式指定，比如</p>
</blockquote>
<pre><code>export const method = 'POST';

export default (a: number, b: number): number =&gt; {
  return a + b;
}
</code></pre>
<p>这个方案可以使信息更紧凑，同时不影响函数逻辑跑本地单元测试。</p>
</li>
<li>
<p>上面提到的入参参数位置，什么时候在 <code>queryString</code>，什么时候在其他？</p>
<blockquote>
<p>遵从大多数的案例，GET 的情况下使用 <code>queryString</code>， 其他情况下在 <code>body</code></p>
</blockquote>
<blockquote>
<p>当然还有完全自定义的方案，为避广告嫌疑就不展开了，基本原则还是不影响函数核心逻辑和单元测试。</p>
</blockquote>
</li>
<li>
<p>上面提到的 入参参数类型 ，有什么应用场景？</p>
<blockquote>
<p>有了这个信息，如果你喜欢 <code>Joi</code>， 应该能很容易生成参数校验的代码了。</p>
</blockquote>
<blockquote>
<p>或者有自己想法的话，和我一样，自己实现一套 <code>validator</code> 也不是什么难事。</p>
</blockquote>
</li>
</ul>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
