HTTP报文详解

2,130 阅读9分钟

HTTP报文详解

HTTP有两种报文:请求报文和响应报文,具体介绍如下。 HTTP消息是服务器和客户端之间交换数据的方式。 有两种类型的消息︰ 请求(requests)--由客户端发送用来触发一个服务器上的动作;响应(responses)--来自服务器的应答。

一、HTTP请求报文

咋先上个图再细细分析。

HTTP请求报文主要包括请求行、请求头部以及请求的数据(实体)三部分。

请求行(HTTP请求报文的第一行)

请求行由方法字段、URL字段和HTTP协议版本字段。其中,方法字段严格区分大小写,当前HTTP协议中的方法都是大写。请求行各部分介绍如下:

方法字段

GET:请求获取Request-URI(URI:通用资源标识符,URL是其子集,URI注重的是标识,而URL强调的是位置,可以将URL看成原始的URI),所标识的资源

POST:在Request-URI所标识的资源后附加新的数据;支持HTML表单提交,表单中有用户添入的数据,这些数据会发送到服务器端,由服务器存储至某位置(例如发送处理程序)

HEAD:请求Request-URI所标识的资源响应消息报头,HEAD方法可以在响应时不返回消息体。

PUT:与GET相反,请求服务器存储一个资源,并用Request-URI做为其标识;例如发布系统。

DELETE:请求删除URL指向的资源

OPTIONS:请求查询服务器的性能,或者查询与资源相关的选项 ⑦TRACE:跟踪请求要经过的防火墙、代理或网关等,主要用于测试或诊断

CONNECT:保留将来使用

URL

一个完整的包括类型、主机名和可选路径名的统一资源引用名,如:www.example.com/path/to/fil…

HTTP协议版本

有HTTP/0.9、HTTP/1.0、HTTP/1.1、HTTP/2.0。目前主流版本为HTTP/1.1

请求头部:位于请求行的下面

请求报文中常见的请求头有:

请求头描述
Connetion连接管理
Host标头指定请求资源的主机
Range请求实体的字节范围
User-Agent包含发出请求的用户信息
Accept用户代理期望的MIME 类型列表
Accept-Language列出用户代理期望的页面语言

注:更多的HTTP请求头点击这里

HTTP 消息头允许客户端和服务器通过 request和 response传递附加信息。一个请求头由名称(不区分大小写)后跟一个冒号“:”,冒号后跟具体的值(不带换行符)组成。该值前面的引导空白会被忽略。

自定专用消息头可通过'X-' 前缀来添加;但是这种用法被IETF在2012年6月发布的 RFC5548 中明确弃用,原因是其会在非标准字段成为标准时造成不便;其他的消息头在 IANA 注册表 中列出, 其原始内容在 RFC 4229 中定义。 此外,IANA 还维护着被提议的新HTTP 消息头注册表.

根据不同上下文,可将消息头分为:

General headers: 同时适用于请求和响应消息,但与最终消息主体中传输的数据无关的消息头。

Request headers: 包含更多有关要获取的资源或客户端本身信息的消息头。

Response headers: 包含有关响应的补充信息,如其位置或服务器本身(名称和版本等)的消息头。

Entity headers: 包含有关实体主体的更多信息,比如主体长(Content-Length)度或其MIME类型。

消息头也可以根据代理对其的处理方式分为:

端到端消息头: 这类消息头必须被传输到最终的消息接收者,也即,请求的服务器或响应的客户端。中间的代理服务器必须转发未经修改的端到端消息头,并且必须缓存它们。

逐跳消息头: 这类消息头仅对单次传输连接有意义,不能通过代理或缓存进行重新转发。这些消息头包括 Connection, Keep-Alive, Proxy-Authenticate, Proxy-Authorization, TE, Trailer, Transfer-Encoding 及 Upgrade。注意,只能使用 Connection 来设置逐跳一般头。

HTTP首部:

通用首部:请求和响应都可以使用的;

Connection:定义C/S之间关于请求/响应的有关选项对于http/1.0, Connection: keep-alive

Cache-Control: 缓存指示

实体首部:用于指定实体属性

实体主体用于POST方法中。用户向Web服务器提交表单数据的时候,需要使用POST方法,此时主体中包含用户添写在表单的各个属性字段的值,当Web服务器收到POST方法的HTTP请求报文后,可以从实体中取出需要的属性字段的值。

也就是说,当用户通过Web浏览器向Web服务器发送请求时,Web浏览器会根据用户的具体请求来选择不同的HTTP请求方法,再将相应的URL和HTTP协议版本及相关的标头填入头部行中,若是POST方法,还会将相关的表单数据填入实体主体中,产生一个HTTP请求报文,然后将这个报文发送给Web服务器。

Location: 资源的新位置 Allow: 允许对此资源使用的请求方法

1、内容首部: Content-Encoding:支持的编码 Content-Language:支持的自然语言 Content-Length:文本长度 Content-Location:资源所在位置 Content-Range:在整个资源中此实体表示的字节范围 Content-Type:主体的对象类型

2、缓存首部: ETag: 实体标签 Expires: 过期期限 Last-Modified: 上一次的修改时间

请求首部:

Host: 请求的主机名和端口号,虚拟主机环境下用于不同的虚拟主机

Referer:指明了请求当前资源的原始资源的URL

User-Agent: 用户代理,使用什么工具发出的请求

Accept首部:用户标明客户自己更倾向于支持的能力

  • Accept: 指明服务器能发送的媒体类型
  • Accept-Charset: 支持使用的字符集
  • Accept-Encoding: 支持使用的编码方式
  • Accept-Language: 支持使用语言

条件请求首部:

  • Expect: 告诉服务器能够发送来哪些媒体类型
  • If-Modified-Since: 是否在指定时间以来修改过此资源
  • If-None-Match:如果提供的实体标记与当前文档的实体标记不符,就获取此文档

跟安全相关的请求首部:

  • Authorization: 客户端提交给服务端的认证数据,如帐号和密码
  • Cookie: 客户端发送给服务器端身份标识

下面来看浏览器发出的一个请求。

上图展示一般请求所带有的属性。

我是分割线

二、HTTP响应报文

老规矩,先上图。

HTTP响应报文同样也分为三部分,有状态行、首部行、实体

状态行:HTTP响应报文的第一行

状态行包括三个字段:协议版本、状态码与原因短语。

HTTP 响应状态代码指示特定 HTTP 请求是否已成功完成。响应分为五类:信息响应(100–199),成功响应(200–299),重定向(300–399),客户端错误(400–499)和服务器错误 (500–599)。状态代码由 section 10 of RFC 2616定义。

注:更多状态码含义请点击这里

状态码:

1xx:这一类型的状态码,代表请求已被接受,需要继续处理。这类响应是临时响应,只包含状态行和某些可选的响应头信息,并以空行结束。

2xx: 这一类型的状态码,代表请求已成功被服务器接收、理解、并接受。

3xx: 这类状态码代表需要客户端采取进一步的操作才能完成请求。通常,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的Location域中指明。

4xx: 这类的状态码代表客户端类的错误

5xx: 服务器类的错误。

响应首部(首部行):位于响应报文状态行之后

Date标头:消息产生的时间

Age标头:(从最初创建开始)响应持续时间

Server标头: 向客户端标明服务器程序名称和版本

ETage标头:不透明验证者

Location标头:URL备用的位置

Content-Length标头:实体的长度

Content-Type标头:实体的媒体类型

协商首部:

  • Accept-Ranges: 对当前资源来讲,服务器所能够接受的范围类型
  • Vary: 首部列表,服务器会根据列表中的内容挑选出最适合的版本发送给客户端

跟安全相关的响应首部:

  • Set-Cookie: 服务器端在某客户端第一次请求时发给令牌
  • WWW-Authentication: 质询,即要求客户提供帐号和密码

响应首部一般包含如下内容:

我是分割线

三、实战部分

对于HTTP协议:

我们知道超文本传输协议(Hypertext Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII形式给出;而消息内容则具有一个类似MIME的格式。

那么问题来了,我们是否可以连立一个建立一个tcp连接,然后拼接报文利用socket发送到web服务器,服务器能够解析和响应吗?

答案是可以的。

1、获取目标地址

说干就干,就拿度娘下手吧。 首先我们先拿到度娘的ip,因为HTTP协议中必须要有Host请求头。

ping www.baidu.com

Shell交互如下:

2、组装报文

按照第一节中的HTTP请求报文,我们组装报文。

echo -e 'GET / HTTP/1.1\r\nHost: 163.177.151.110:80\r\n\r\n'

注:-e 参数是将\r\n这类字符进行转义

3、建立TCP连接

exec 8<>/dev/tcp/163.177.151.110/80

注:有一个特殊的文件/dev/tcp,打开这个文件就类似于发出了一个socket调用,建立一个socket连接,读写这个文件就相当于在这个socket连接中传输数据。

4、向Socket中写数据

向刚刚建立的Socket中写入刚刚准备好的数据

echo -e 'GET / HTTP/1.1\r\nHost: 163.177.151.110:80\r\n\r\n' >&8

5、读取响应数据

我们使用cat命令从文件描述符8中读取数据。

下面见证奇迹的时刻:

cat <&8

6、关闭连接

exec 8<&-

四、最后

文章到这就结束了,我的水平有限,我也不知道能帮助大家多少,到最后希望大家给个反馈吧,让我有创作的动力。

新年将至,希望大家都能在新的一年里牛气冲天,牛年大吉。

最后,能看到这里的小伙伴顺手点个吧。

参考资料:

  1. HTTP文档-MDN
  2. HTTP-百度百科
  3. HTTP消息-菜鸟教程