HTTP(Hypertext Transfer Protocol)는 웹의 생명입니다. 문서가 전송되거나 AJAX 요청이 있을 때마다 사용됩니다. 그러나 놀랍게도 일부 웹 개발자들 사이에서는 HTTP가 상대적으로 알려지지 않았습니다. 이 소개에서는 일련의 REST 설계 원칙이 HTTP를 어떻게 뒷받침하는지 보여줍니다. 거의 모든 장치나 운영 체제에서 사용할 수 있는 인터페이스를 구축하여 모든 기능을 최대한 활용하는 방법을 배우게 됩니다. Envato Market에는 서버에 설치하여 사용자 정의 단축 URL을 생성할 수 있는 PHP 스크립트인 프리미엄 URL 단축기와 같이 웹 개발에 도움이 되는 수천 개의 유용한 코드 스크립트, 플러그인 및 앱도 있습니다. 휴식을 취하는 이유는 무엇인가요? REST는 독립 시스템 간의 상호 작용을 구성하는 간단한 방법입니다. 2005년부터 인기가 높아졌으며 Twitter API와 같은 서비스 디자인에 영감을 주었습니다. REST를 사용하면 최소한의 오버헤드로 휴대폰, 기타 웹사이트 등 다양한 클라이언트와 상호 작용할 수 있기 때문입니다. 이론적으로 REST는 웹에 묶여 있지 않지만 거의 항상 이런 방식으로 구현되며 HTTP에서 영감을 받았습니다. 따라서 REST는 HTTP를 사용할 수 있는 모든 곳에서 사용할 수 있습니다. 또 다른 옵션은 HTTP 위에 상대적으로 복잡한 규칙을 구축하는 것입니다. 종종 이것은 완전히 새로운 언어로 나타납니다. 가장 대표적인 예는 SOAP와 GraphQL입니다. 완전히 새로운 규칙을 배워야 하지만 HTTP를 최대한 활용할 수는 없습니다. REST는 HTTP에서 영감을 얻고 HTTP의 장점을 활용하기 때문에 HTTP 작동 방식을 이해하는 가장 좋은 방법입니다. 이 초기 개요 후에는 URL, HTTP 동사, 응답 코드 등 각 HTTP 구성 요소를 살펴보겠습니다. 또한 이를 RESTful 방식으로 사용하는 방법도 검토하겠습니다. 그 과정에서 웹 인터페이스를 통해 회사의 고객과 관련된 데이터를 추적하는 프로세스를 시뮬레이션하는 샘플 애플리케이션을 사용하여 이론을 설명하겠습니다. HTTP HTTP는 웹을 통해 문서를 주고받을 수 있는 프로토콜입니다. 프로토콜은 교환할 수 있는 메시지와 다른 메시지에 대한 적절한 응답을 결정하는 규칙 집합입니다. 하드 드라이브에 이메일을 가져오는 데 사용할 수 있는 또 다른 일반적인 프로토콜은 POP3입니다. HTTP에는 서버와 클라이언트라는 두 가지 역할이 있습니다. 일반적으로 대화는 항상 클라이언트에 의해 시작됩니다. HTTP는 텍스트 기반입니다. 즉, 메시지 본문에는 다른 미디어가 포함될 수도 있지만 메시지는 본질적으로 텍스트의 일부입니다. HTTP 교환은 텍스트를 사용하여 쉽게 모니터링할 수 있습니다. HTTP 메시지는 헤더와 본문으로 구성됩니다. 본문은 비어 있는 경우가 많습니다. 헤더의 지침에 따라 사용할 수 있도록 네트워크를 통해 전송하려는 데이터가 포함되어 있습니다. 헤더에는 인코딩 정보와 같은 메타데이터가 포함되어 있지만 요청의 경우 중요한 HTTP 메서드도 포함되어 있습니다. RESTful 스타일에서는 헤더 데이터가 본문보다 더 중요한 경우가 많습니다. 직장에서 HTTP 모니터링 Chrome 또는 Firefox 개발자 도구를 사용하는 경우 상단 표시줄에서 네트워크를 클릭하면 현재 사용 중인 사이트의 HTTP 요청을 볼 수 있습니다. 로그를 보려면 웹 개발자 도구를 연 상태에서 페이지를 새로 고쳐야 할 수도 있습니다. 예: HTTP에 익숙해지는 또 다른 유용한 방법은 cURL과 같은 전용 클라이언트를 사용하는 것입니다. cURL은 모든 주요 운영 체제에서 사용할 수 있는 명령줄 도구입니다. cURL을 설치한 후 다음을 입력하세요. 으아악 전체 HTTP 대화가 표시됩니다. 요청 앞에는 >,而响应前面是 가 붙습니다. 웹사이트 URL은 작업하려는 콘텐츠를 식별하는 방법입니다. 각 URL은 리소스를 식별한다고 말합니다. 이러한 URL은 웹페이지에 할당된 URL과 정확히 동일합니다. 실제로 웹페이지는 리소스입니다. 좀 더 멋진 예를 들어 회사의 고객 목록을 관리하는 샘플 애플리케이션을 고려해 보겠습니다. /clients 将识别所有客户端,而 /clients/jim "Jim"이라는 고객이 해당 이름을 가진 유일한 고객이라는 가정 하에 인식됩니다. 이 예에서는 인터페이스 구성 방식의 관점에서 중요하지 않기 때문에 일반적으로 URL에 호스트 이름을 포함하지 않습니다. 그럼에도 불구하고 리소스 식별자가 네트워크 전체에서 고유한지 확인하려면 호스트 이름이 중요합니다. 우리는 종종 호스트에 리소스 요청을 보낸다고 말합니다. 호스트는 요청 헤더 바로 위에 있는 리소스 경로와 별도로 헤더에 포함됩니다. 으아악 자원은 명사로 생각하는 것이 가장 좋습니다. 예를 들어 다음은 RESTful이 아닙니다. 으아악 동작을 설명하기 위해 URL을 사용하기 때문입니다. 이는 RESTful이 아닌 시스템과 RESTful을 구별하는 매우 기본적인 사항입니다. 마지막으로, URL은 필요한 만큼 정확해야 합니다. 리소스를 고유하게 식별하는 데 필요한 모든 것이 URL에 포함되어야 합니다. 요청에 리소스를 식별하는 데이터를 포함할 필요는 없습니다. 이러한 방식으로 URL은 애플리케이션에서 처리되는 모든 데이터의 완전한 맵 역할을 합니다. 但是如何指定操作呢?例如,您怎么说您希望创建而不是检索新的客户记录?这就是 HTTP 动词发挥作用的地方。 HTTP 动词 每个请求在请求标头中指定特定的 HTTP 动词或方法。这是请求标头中的第一个全大写单词。例如,GET / HTTP/1.1 表示正在使用 GET 方法,而 DELETE /clients/anne HTTP/1.1 表示正在使用 DELETE 方法。 HTTP 动词告诉服务器如何处理 URL 标识的数据。请求可以选择在其正文中包含执行操作可能需要的其他信息,例如您想要与资源一起存储的数据。您可以使用 -d 选项在 cURL 中提供此数据。 如果您曾经创建过 HTML 表单,您就会熟悉两个最重要的 HTTP 动词:GET 和 POST。但可用的 HTTP 动词要多得多。构建 RESTful API 最重要的是 GET、POST、PUT 和 DELETE。还有其他方法,例如 HEAD 和 OPTIONS,但比较少见。如果您想了解所有其他 HTTP 方法,官方来源是 IETF。 获取 GET 是最简单的 HTTP 请求方法,浏览器每次单击链接或在地址栏中输入 URL 时都会使用该方法。它指示服务器将 URL 标识的数据传输到客户端。切勿因 GET 请求而在服务器端修改数据。从这个意义上说,GET 请求是只读的,但是当然,一旦客户端收到数据,它就可以自由地在自己这边对其进行任何操作 - 例如,将其格式化以供显示。 放置 当您希望创建或更新由 URL 标识的资源时,将使用 PUT 请求。例如, PUT /clients/robin 可能会在服务器上创建一个名为 Robin 的客户端。您会注意到 REST 完全与后端无关;请求中没有任何内容告诉服务器应该如何创建数据——只是告诉服务器应该如何创建数据。这使您可以在需要时轻松更换后端技术。 PUT 请求包含在主体中更新或创建资源时使用的数据。在 cURL 中,您可以使用 -d 开关将数据添加到请求: curl -v -X PUT -d "some text" 로그인 후 복사 删除 DELETE 应该执行与 PUT 相反的操作;当您想要删除由请求的 URL 标识的资源时,应该使用它。 curl -v -X DELETE /clients/anne 로그인 후 복사 这将删除与该资源关联的所有数据,由 /clients/anne 标识。 发布 POST 当您希望在服务器上进行的处理应该重复时使用,如果 POST 请求被重复(也就是说,它们不是幂等;更多内容请参见下文) )。此外,POST 请求应导致将请求正文作为您要发布到的 URL 的下属进行处理。 简单来说,POST /clients/ 不应导致 /clients/ 本身的资源被修改,而是 URL 以 /clients/ 开头的资源被修改。例如,它可以将一个新客户端附加到列表中,并使用服务器生成的 id: /clients/some-unique-id 로그인 후 복사 PUT 请求很容易使用,而不是 POST 请求,反之亦然。有些系统仅使用一个,有些系统使用 POST 进行创建操作,使用 PUT 进行更新操作(因为 PUT 要求您始终提供完整的 URL),有些系统甚至使用 POST 进行更新,并使用 PUT用于创建。 通常,POST 请求用于触发服务器上不符合 Create/Update/Delete 范例的操作,但这超出了 REST 的范围。在我们的示例中,我们将始终使用 PUT。 HTTP 方法分类 安全和不安全的方法 安全方法是那些从不修改资源的方法。从上面列出的四种方法中,唯一安全的方法是 GET。其他的不安全,因为它们可能会导致资源的修改。 幂等方法 无论重复请求多少次,这些方法都会获得相同的结果:它们是 GET、PUT 和 DELETE。唯一的非幂等方法是 POST。 PUT 和 DELETE 被认为是幂等的可能会令人惊讶,但这很容易解释。使用相同的主体重复 PUT 方法应该以与上一个 PUT 请求中描述的方式相同的方式修改资源:不会有任何改变!同样,删除一个资源两次也是没有意义的。因此,无论重复 PUT 或 DELETE 请求多少次,结果都应该与只执行一次相同。 记住:最终决定使用某种 HTTP 方法时会发生什么情况的是程序员。 HTTP 实现中没有任何固有的东西会自动导致资源被创建、列出、删除或更新。您必须小心地正确应用 HTTP 协议并自行强制执行这些语义。 表示 我们可以通过以下方式总结到目前为止所学到的知识:HTTP 客户端和 HTTP 服务器交换有关由 URL 标识的资源的信息。 我们说请求和响应包含资源的表示。通过表示,我们指的是某种格式的有关资源状态或该状态未来应如何的信息。标头和正文都是表示的一部分。 包含元数据的 HTTP 标头由 HTTP 规范严格定义;它们只能包含纯文本,并且必须以某种方式格式化。 正文可以包含任何格式的数据,这就是 HTTP 真正发挥作用的地方。您知道可以用任何人类语言发送纯文本、图片、HTML 和 XML。通过请求元数据或不同的 URL,您可以选择同一资源的不同表示形式。例如,您可以将网页发送到浏览器,并将 JSON 发送到应用程序。 HTTP 响应应指定正文的内容类型。这是在标头的 Content-Type 字段中完成的。例如: Content-Type: application/json 로그인 후 복사 为简单起见,我们的示例应用程序仅来回发送 JSON,但应用程序的设计方式应使您可以轻松更改数据格式,以适应不同的客户端或用户偏好。 HTTP 客户端库 要尝试不同的请求方法,您需要一个客户端,它允许您指定要使用的方法。不幸的是,HTML 表单不符合要求,因为它们只允许您发出 GET 和 POST 请求。在现实生活中,API 是通过单独的客户端应用程序或通过浏览器中的 JavaScript 以编程方式访问的。 这就是为什么除了服务器之外,在您选择的编程语言中拥有良好的 HTTP 客户端功能也很重要。 一个非常流行的 HTTP 客户端库是 cURL。您已经在本教程前面熟悉了 cURL 命令。 cURL 包括一个独立的命令行程序和一个可供各种编程语言使用的库。特别是,cURL 通常是 PHP 开发人员选择的 HTTP 客户端解决方案。其他语言(例如 Python)提供更多本机 HTTP 客户端库。 设置示例应用程序 现在我们将构建一个准系统示例应用程序。您可以按照相应部分并使用代码附件中的相应文件夹,在 Node.js 或 PHP 中构建示例应用程序。两个应用程序的工作方式相同。如果您不确定选择哪个,Node.js 可能是更好的选择,因为它现在更常用。 Node.js 和 Express 为了运行示例应用程序,您需要安装 Node.js。完成后,打开源代码附件中的 node.js 目录并运行 npm install。 PHP 要运行示例应用程序,您需要安装 PHP 5 和具有某种运行 PHP 机制的 Web 服务器。当前版本必须至少为 5.2 版本才能访问 json_encode() 和 json_decode() 函数。 对于服务器,最常见的选择仍然是 Apache 和 mod_php,但您可以自由地使用您喜欢的任何替代方案。有一个 Apache 配置示例,其中包含重写规则,可帮助您快速设置应用程序。对任何以 /clients/ 开头的 URL 的所有请求都必须路由到我们的 server.php 文件。 在 Apache 中,您需要启用 mod_rewrite 并将提供的 mod_rewrite 配置放在您的 Apache 配置或 .htacess 中的某个位置文件。这样,server.php 将响应来自服务器的所有请求。必须使用 Nginx 或您决定使用的任何替代服务器来实现同样的效果。 示例应用程序如何工作 Node.js 和 Express 如果你查看代码,你会看到一些不同的方法,例如 app.get 或 app.put。这些是不同的路线。每个路由都匹配特定的 URL 和 HTTP 方法。 app.get("/clients", (_, res) => { ... }); app.get("/clients/:client", (req, res) => { ... }); app.put("/clients/:client", (req, res) => { ... }); app.delete("/clients/:client", (req, res) => { ... }); 로그인 후 복사 您可能已经注意到 URL 中的 :client 。这是一个参数,这意味着 URL 该部分中的任何内容都将与该路由匹配,并且 URL 该部分将作为参数传递。在路由处理函数内部,您可以看到描述逻辑的注释。最后是app.listen。 app.listen(port, () => { console.log(`Example app listening on port ${port}`); }); 로그인 후 복사 这将在 port 指定的端口启动服务器。回调函数在服务器启动后执行。 PHP 以 REST 方式处理请求有两个关键。第一个关键是根据 HTTP 方法启动不同的处理 - 即使 URL 相同。在 PHP 中,$_SERVER 全局数组中有一个变量,用于确定使用哪种方法发出请求: $_SERVER['REQUEST_METHOD'] 로그인 후 복사 此变量包含字符串形式的方法名称,例如 'GET'、'PUT' 等。 另一个关键是知道请求的是哪个 URL。为此,我们使用另一个标准 PHP 变量: $_SERVER['REQUEST_URI'] 로그인 후 복사 此变量包含从第一个正斜杠开始的 URL。例如,如果主机名是 example.com,则 'https://example.com/' 将返回 '/',而 'http://example.com/test/ ' 将返回 '/test/'。 我们首先尝试确定调用了哪个 URL。我们只考虑以 'clients' 开头的 URL。其他均无效。 $resource = array_shift($paths); if ($resource == 'clients') { $name = array_shift($paths); if (empty($name)) { $this->handle_base($method); } else { $this->handle_name($method, $name); } } else { // We only handle resources under 'clients' header('HTTP/1.1 404 Not Found'); } 로그인 후 복사 我们有两种可能的结果: 资源就是客户,在这种情况下,我们会返回完整的列表。 还有一个进一步的标识符。 如果有其他标识符,我们假设它是客户端的名称,并再次将其转发到不同的函数,具体取决于 方法 。我们使用 switch 语句,在实际应用程序中应该避免这种情况: switch($method) { case 'PUT': $this->create_contact($name); break; case 'DELETE': $this->delete_contact($name); break; case 'GET': $this->display_contact($name); break; default: header('HTTP/1.1 405 Method Not Allowed'); header('Allow: GET, PUT, DELETE'); break; } 로그인 후 복사 响应代码 您可能已经注意到,示例应用程序使用 PHP header(),传递一些看起来奇怪的字符串作为参数。 header() 函数打印 HTTP headers 并确保它们的格式正确。标头应该是响应中的第一件事,因此在完成标头之前不应输出任何其他内容。有时,除了您在代码中指定的标头之外,您的 HTTP 服务器可能会配置为添加其他标头。 标头包含各种元信息,例如消息正文中使用的文本编码或正文内容的 MIME 类型。在本例中,我们显式指定 HTTP 响应代码。 HTTP 响应代码标准化了一种通知客户端请求结果的方法。默认情况下,PHP返回200响应码,表示响应成功。 服务器应该返回最合适的HTTP响应代码;这样,客户端可以尝试修复其错误(假设有任何错误)。大多数人都熟悉常见的 404 Not Found 响应代码,但还有更多可用的代码可以适应各种情况。 请记住,HTTP 响应代码的含义并不是非常精确;这是 HTTP 本身相当通用的结果。您应该尝试使用与当前情况最匹配的响应代码。话虽如此,如果您找不到完全合适的产品,也不必太担心。 以下是一些经常与 REST 一起使用的 HTTP 响应代码: 200 好的 此响应代码表明请求成功。 201已创建 这表明请求成功并且资源已创建。用于确认 PUT 或 POST 请求是否成功。 400 错误请求 请求格式错误。当数据未通过验证或格式错误时,尤其是在 POST 和 PUT 请求中,会发生这种情况。 404 未找到 此响应表明无法找到所需的资源。这通常会返回给所有指向没有相应资源的 URL 的请求。 401 未经授权 此错误表明您需要在访问资源之前执行身份验证。 405 方法不允许 此资源不支持所使用的 HTTP 方法。 409 冲突 这表明存在冲突。例如,您使用 PUT 请求两次创建相同的资源。 500 内部服务器错误 当一切都失败时;一般情况下,500响应是由于服务器端出现意外情况导致处理失败,导致服务器出错时使用的。 练习示例应用程序 我们首先从应用程序中获取信息。我们需要客户端 'jim' 的详细信息,因此让我们向此资源的 URL 发送一个简单的 GET 请求: curl -v http://localhost:80/clients/jim 로그인 후 복사 这将显示完整的消息标题。响应中的最后一行将是消息正文;在本例中,它将是包含 Jim 地址的 JSON(请记住,省略方法名称将导致 GET 请求;同时将 localhost:80 替换为您正在使用的服务器名称和端口)。 接下来,我们可以一次性获取所有客户的信息: curl -v http://localhost:80/clients/ 로그인 후 복사 然后我们创建一个新客户端,名为 Paul: curl -v -X "PUT" http://localhost:80/clients/paul -d '{"address":"Sunset Boulevard" }' -H 'content-type: application/json' 로그인 후 복사 现在您将收到包含 Paul 的所有客户的列表作为确认。 最后,删除客户端: curl -v -X "DELETE" http://localhost:80/clients/anne 로그인 후 복사 您会发现返回的JSON不再包含有关Anne的任何数据。 如果您尝试检索不存在的客户端,例如: curl -v http://localhost:80/clients/jerry 로그인 후 복사 您将收到 404 错误,而如果您尝试创建已存在的客户端: curl -v -X "PUT" http://localhost:80/clients/anne 로그인 후 복사 您将收到 409 错误。 结论 重要的是要记住,HTTP 被设计为在除了对协议的理解之外不共享任何内容的系统之间进行通信。一般来说,您对 HTTP 之外的假设越少越好:这允许最广泛的程序和设备访问您的 API。 저는 이 튜토리얼에서 PHP를 사용하고 있습니다. 왜냐하면 이것이 Envato Tuts+ 독자들에게 가장 친숙한 언어일 것이기 때문입니다. 즉, PHP는 웹용으로 설계되었지만 PUT 请求的方式与 GET 和 POST를 완전히 다르게 처리하기 때문에 RESTful 방식으로 작업할 때 최고의 언어가 아닐 수 있습니다. PHP 및 Node.js 외에도 다음 사항도 고려할 수 있습니다. 더 높은 성능의 웹 서버를 찾고 있습니다. 다양한 Ruby 프레임워크(Rails 및 Sinatra). Python은 REST를 잘 지원하기 때문입니다. Plain Django와 WebOb 또는 Werkzeug가 작동해야 합니다. REST 원칙을 고수하려는 애플리케이션 중에서 전형적인 예는 Atom 게시 프로토콜이지만, 솔직히 말해서 실제로는 자주 사용되지 않습니다. HTTP를 최대한 활용한다는 아이디어를 바탕으로 구축된 최신 애플리케이션에 대해서는 Apache CouchDB를 참조하세요. 재미있게 보내세요! 이 기사는 Jacob Jackson의 기여로 업데이트되었습니다. Jacob은 웹 개발자이자 기술 작가이며 오픈 소스에 자주 기여하고 있습니다.