网络协议-HTTP协议详解-HTTP报文组成结构(请求方法、响应状态码)

时间:2020-05-28
本文章向大家介绍网络协议-HTTP协议详解-HTTP报文组成结构(请求方法、响应状态码),主要包括网络协议-HTTP协议详解-HTTP报文组成结构(请求方法、响应状态码)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

HTTP 报文简介

用于 HTTP 协议交互的信息被称为 HTTP 报文,请求端(客户端)发起的 HTTP 报文叫做请求报文,响应端(服务器端)发出的 HTTP 报文叫做响应报文。请求报文会向 Web 服务器请求一个动作,响应报文会将请求的处理结果返回给客户端。

HTTP 报文本身是由多行(用CR+LF作换行符,即\r\n)数据构成的字符串文本,这些文本信息描述了报文的内容及含义,后面跟着可选的数据部分。

HTTP 报文大致可分为报文首部和报文主体两块,两者由首次出现的空行来分隔,通常,并不一定要有报文主体,比如 GET 请求就没有:

而 POST 请求则包含报文主体:

正常的响应报文通常都包含报文主体:

HTTP 报文组成结构

了解了 HTTP 报文的基本概念后,下面我们具体分析 HTTP 报文的组成结构。

HTTP 报文是简单的格式化数据块:

报文分为请求报文和响应报文,二者结构类似,都由三部分构成 —— 对报文进行描述的起始行、包含属性的首部字段、以及可选的包含数据的报文主体部分:

通常我们可以将请求报文的起始行称作请求行,对应的报文主体称作请求主体;将响应报文的起始行称作状态行(包含状态码),对应的报文主体称作响应主体。首部字段又可以细分为请求首部字段、响应首部字段、通用首部字段和实体首部字段,关于首部字段的含义及使用后面我们会详细介绍。

我们以 http://laravel58.test/ 为例,其请求报文的组成结构如下:

对应的响应报文组成结构如下:

起始行与首部字段之间通过一个换行符分隔(CR+LF),多个首部字段之间也是通过换行符分隔,报文首部与报文主体之间则通过一个一个空行分隔(两个CR+LF),报文首部有纯文本格式的字符串组成,报文主体则可以包含多种格式数据。

请求报文可以抽象为如下格式:

<method> <request-URL> <version>(请求行)
<headers>

<entity-body>

响应报文可以抽象如下格式:

<version> <status-code> <reason-phrase>(响应行)
<headers>

<entity-body>

下面是对各部分的简单描述:

  • 方法(method):客户端希望服务器对资源执行的动作,比如 GET、POST、PUT、DELETE 等;
  • 请求 URL(request-URL):命名了所请求资源,或者 URL 路径组成的完整 URL,比如 http://laravel58.test/ 这个示例中是 /;
  • 版本(version):HTTP 版本,目前主流版本是 1.1;
  • 状态码(status-code):三个数字,描述了请求过程所发生的情况,例如 200、404、500 等;
  • 原因短语(reason-phrase):数字状态码的可读版本;
  • 首部字段(headers):可以有零个或多个首部,每个首部都包含一个名字,后面跟着一个冒号,然后是一个可选的空格,接着是一个值,最后是一个 CR+LF(即\r\n),报文首部是由一个空行结束的,表示了首部列表的结束和实体主体部分的开始;
  • 主体(entity-body):包含一个由任意数据组成的数据块,并不是所有报文都包含实体的主体部分。

HTTP 请求方法

在请求报文的第一行第一个元素就是 HTTP 方法,HTTP 协议主要支持的方法包括以下这些:

今天我们将就这些常见的 HTTP 方法的使用和注意事项进行介绍。在整篇教程中,我们将基于 TELNET 工具模拟 HTTP 通信或者通过抓包工具分析请求报文和响应报文,以便让你有更直观的感受。

GET

GET 方法用于从服务器上获取指定的 URL 资源:

这是我们日常最常见的 HTTP 方法了,由于 GET 请求不会对服务器资源产生副作用(只是获取资源,不会对资源进行变更,但是这一点需要开发者保证,通过 GET 请求变更服务器资源有重大安全隐患,在开发过程中国要避免这么做),所以我们通常将其称为安全的 HTTP 方法,而与之相对的,将 PUT、POST、DELETE、PATCH 这些会对服务器资源造成变更的方法称作不安全的 HTTP 方法。

HEAD 方法和 GET 方法类似,但只返回 HTTP 首部,不返回报文主体部分,通常用于确认 URL 的有效性及资源更新的日期时间等:

显然,和 GET 方法一样,HEAD 方法也是安全的 HTTP 方法。

POST

POST 方法用来向服务器发送数据,通常用它来支持 HTML 的表单,POST 请求会对服务器资源进行变更(这一点需要开发者保证,HTTP 协议本身没有强制要求这么做,你完全可以通过 GET 请求发送数据,但是从安全角度说,强烈建议这么做,即用 POST 方法发送变更资源的请求),是不安全的 HTTP 方法。

我们以 Laravel 框架自带的注册页面为例:

点击注册按钮,即可提交表单,这里使用的是 POST 方法:

PUT

PUT 方法设计的初衷是用来传输文件,就像 FTP 协议的文件上传一样,要求在报文的主体中包含文件内容,然后保存到请求 URI 指定的位置。但是,由于 PUT 方法自身不带验证机制,任何人都可以上传文件,存在安全性问题,因此一般 Web 网站不会通过该方法来上传文件。若配合 Web 应用程序的验证机制,则可能会开放使用 PUT 方法。

PUT 方法的语义就是让服务器用请求主体部分来创建一个由所请求的 URL 命令的新文档,或者,如果那个 URL 已经存在的话,就用这个主体来替代它,因此,我们会看到在 RESTful 架构中,我们一般使用 PUT 方法来更新资源,Laravel 框架中的资源控制器就是这么做的。

与 PUT 方法类似的还有一个 PATCH 方法,用于对指定资源进行部分修改(PUT 方法用于整体覆盖),但是日常开发中,我们不会分的这么细,通常,可以用 PATCH 的地方,往往就可以用 PUT 方法替代。

和 POST 方法一样,PUT 方法也是不安全的 HTTP 方法。具体请求和响应报文格式和 POST 类似,这里不再重复演示了。

需要注意的是,在 Nginx 中,默认只支持对静态资源进行 GET、POST、HEAD 请求,其他 HTTP 方法都会返回 405 Method Not Allowed,要支持的其他 HTTP 方法的话需要配置。所以你会看到在 Laravel 框架中都是通过方法伪造来实现 PUT、DELETE 请求。

DELETE

DELETE 方法设计的初衷是用来删除文件,是与 PUT 请求相对的方法,DELETE 方法按请求 URI 删除指定的资源。但是,HTTP/1.1 的 DELETE 方法和 PUT 方法一样不带验证机制,所以一般 Web 网站也不使用 DELETE 方法进行文件删除,当配合 Web 应用程序的验证机制,或遵守 REST 标准时还是有可能会开放使用的。

目前我们会在 RESTful 架构中,通过 DELETE 方法来删除资源(不一定是文件),Laravel 框架中的资源控制器就是这么做的。DELETE 请求报文中不需要报文实体,只需要通过 URL 来定位资源即可。和 PUT 方法一样,我们需要在 HTML 表单中伪造 DELETE 方法才能让 Nginx 支持 DELETE 请求。

和 POST 方法一样,DELETE 方法也是不安全的 HTTP 方法。

OPTIONS

OPTIONS 方法用来查询针对请求 URL 指定的资源支持的所有 HTTP 方法。Nginx 默认也不支持对资源发起 OPTIONS 请求,我们可以通过在 Laravel 项目中 PHP 内置的 Web 服务器来模拟 OPTIONS 请求,首先通过 php artisan serve 启动内置服务器,然后通过 TELNET 进行模拟通信:

可以看到,在指定 URL 资源 /api/task/1 上支持多个 HTTP 方法。

TRACE

客户端发起一个请求时,这个请求可能要穿过防火墙、代理、网关或其他一些应用程序,每个中间节点都可能会修改原始的 HTTP 请求,TRACE 方法允许客户端在最终请求发送给服务器时,看看它变成了什么样子。该命令主要用于 HTTP 通信的诊断和调试。

TRACE 请求会在目标服务器端发起一个「环回」诊断,行程最后一站的服务器会返回一条 TRACE 响应,并在响应主体中携带它收到的原始请求报文,这样,客户端就可以查看在所有中间 HTTP 应用程序组成的请求/响应链上,原始报文是否以及如何被修改过。

发送 TRACE 请求时,可以在 Max-Forwards 首部字段中填入数值,每经过一个服务器/中间节点该数值就会减1,当数值刚好减到0时,就停止继续传输,最后接收到请求的服务器/节点则返回状态码 200 OK 的响应(不管是否到达最终目标服务器都会返回,不会再继续传递请求)。

但是,TRACE 方法并不怎么常用,再加上容易引发 XST(Cross-Site Tracing,跨站追踪)攻击,就更不会用到了。

HTTP 响应状态码

状态码概述

当目前为止,我们已经介绍完了 HTTP 请求报文起始行的所有元素,第一个是请求方法,第二个是标识请求资源的 URL(一般来说是相对于域名的相对 URL,Web 服务器会将其和请求首部里的 Host 字段组合拼接成完整 URL),第三个是客户端 HTTP 协议的版本,关于报文首部我们放到下一篇统一介绍,现在我们跳到响应报文的起始行,前面学院君已经简单介绍过,响应报文的起始行也由三部分组成,分别是服务器 HTTP 协议的版本,响应状态码以及原因短语,HTTP 协议的版本我们已经讨论过,响应短语主要是响应状态码的可读版本,所以我们重点关注响应状态码。

状态码的职责是当客户端向服务器端发送请求时,描述返回的处理结果,借助状态码,用户可以知道服务器端是正常处理了请求还是出现了错误。

状态码由3位数字组成,按照首数字可以将响应分类如下:

RFC2616 上记录的 HTTP 状态码有 40 种,再加上 WebDAV(基于万维网的分布式创作和版本控制,RFC49185842)和附加 HTTP 状态码(RFC6585)等扩展,数量达60余种,但常用的大概只有14种。下面我们就常见的状态码进行介绍。

1XX:信息性状态码

信息性状态码日常很少见,主要有如下两个:

  • 100:说明收到请求的初始部分,请客户端继续,比如客户端要发送一个请求实体给服务器,但想在发送之前查看下服务器是否会接收这个实体;
  • 101:说明服务器正在根据客户端的指定,将协议切换成 Upgrade 首部所列的协议。

2XX:成功状态码

2XX 的响应结果表明请求被服务器正常处理了。常见的 2XX 状态码如下所示:

  • 200:表明从客户端发来的请求在服务器端被正常处理了;
  • 201:用于创建服务器对象的请求(如 PUT 请求);
  • 202:请求已被接收,但服务器还未对其执行任何动作;
  • 203:表明实体部分包含的信息不是来自源端服务器,而是来自资源的一份副本;
  • 204:该状态码代表服务器接收的请求已经成功处理,但在返回的响应报文中不含实体的主体部分;
  • 205:负责告知浏览器清除当前页面中的所有 HTML 表单元素;
  • 206:该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的 GET 请求,响应报文中由 Content-Range 指定范围的实体内容。

3XX:重定向状态码

3XX 响应结果表明浏览器需要执行某些特殊的处理以正确处理请求,比如对请求进行重定向,常见的 3XX 状态码如下所示:

  • 300:客户端请求一个实际指向多个资源的 URL 时返回这个状态码;
  • 301:永久性重定向,该状态码表示请求的资源已经被分配了新的 URL,以后应使用资源现在所指的 URL;
  • 302:临时性重定向,该状态码表示请求的资源已被分配了新的 URL,希望用户能使用新的 URL 访问,和 - 301 状态码类似,但 302 状态码代表的资源不是被永久移动,只是临时性质的;
  • 303:该状态码表示由于请求对应的资源存在着另一个 URL,应使用 GET 方法定向获取请求的资源,303 状态码和 302 状态码有着相同的功能,但 303 状态码明确表示客户端应当采用 GET 方法获取资源,这点和 302 状态码有所区别;
  • 304:该状态码表示客户端发送附带条件的请求(If-Match、If-Modified-Since、If-None-Match、If-Range、If-Unmodified-Since)时,服务器端允许请求访问资源,但未满足条件的情况下,304 状态码返回时,不包含任何响应的主体部分,常用做客户端缓存。304 虽然被划分在 3XX 类别中,但是与重定向没有任何关系;
  • 305:用来说明必须通过一个代理来访问资源,代理的位置由 Location 首部指定;
  • 307:临时重定向,该状态码与 302 有着相同的含义,尽管 302 标准禁止 POST 变成 GET,但实际使用时大家都不遵守。307 会遵照浏览器标准,不会从 POST 变成 GET,但是对于处理响应时的行为,每种浏览器都有可能出现不同的情况。

注:当 301、302、303 响应状态码返回时,几乎所有浏览器都会把 POST 改成 GET,并删除请求报文内的主体,之后请求会自动再次发送。

4XX:客户端错误状态码

4XX 的响应结果表示客户端是发生错误的原因所在,常见的 4XX 状态码列举如下:

  • 400:该状态码表示请求报文中存在语法错误,当错误发生时,需修改请求的内容后再次发送请求;
  • 401:该状态码表示发送的请求需要有通过 HTTP 认证的认证信息,另外若之前已进行过1次请求,则表示用户认证失败;
  • 402:该状态码暂时还未启用;
  • 403:该状态码表明对请求资源的访问被服务器拒绝了,服务器端没有必要给出拒绝的详细理由,但如果想做说明的话,可以在实体的主体部分对原因进行描述,这样用户就能看到了;
  • 404:该状态码表明服务器上无法找到请求的资源,除此之外,也可以在服务器端拒绝请求且不想说明原因时使用;
  • 405:发起的请求中带有请求 URL 所不支持的请求方法时返回该状态码,上一篇分享中我们已经提及;
  • 406:客户端可以指定参数来说明它们愿意接收什么类型的实体,服务器没有与客户端可接受的 URL 相匹配的资源时,返回此状态码;
  • 407:与 401 状态码类似,但用于要求对资源进行认证的代理服务器;
  • 408:客户端请求超时,服务器返回此状态码并关闭连接;
  • 409:说明请求可能在资源上引发冲突时返回此状态码;
  • 410:与 404 类似,只是服务器曾经拥有过此资源,现在被移除了;
  • 411:服务器要求请求报文中包含 Content-Length 首部时使用;
  • 412:客户端发起条件请求,但其中一个条件失败时使用;
  • 413:客户端发送的实体主体部分超过服务器处理的上限,一般上传大文件时会出现这种情况;
  • 414:客户端发送请求中的请求 URL 超过服务器能处理的长度上限,返回此状态码;
  • 415:服务器无法理解或无法支持客户端所发送实体的内容类型。

5XX:服务器错误状态码

5XX 的响应结果表明服务器本身发生错误,常见的 5XX 状态码如下所示:

  • 500:该状态码表明服务器端在执行请求时发生了错误,也可能是 Web 应用程序存在的 bug 或某些临时的故障;
  • 501:客户端发起的请求超出服务器能力的范围;
  • 502:作为代理或网关使用的服务器从请求响应链的下一条链路上收到了一条伪响应时返回此状态码;
  • 503:该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求,如果事先得知解除以上状况需要的时间,最好写入 Retry-After 首部字段再返回给客户端;
  • 504:与状态码 408 相似,这是这里的响应来自网关或代理,它们在等待另一个服务器对其请求进行响应的时候超时了,比如 php-fpm 故障或没有启动,通过 nginx 访问应用的时候会返回此状态码;
  • 505:服务器收到的请求使用了它无法支持的协议版本时,使用此状态码。

原文地址:https://www.cnblogs.com/stringarray/p/12983880.html