HTTP 报文是在 HTTP 应用程序之间发送的数据块。这些数据块以一些文本形式的元信息开头,这些信息描述了报文的内容及含义。

报文流

报文在客户端、服务器和代理之间的流动称为报文流。 HTTP 使用术语流入和流出来描述事务处理的方向。报文像水一样都是从上游流向下游,不会从下游流向上游。假定客户端和服务器之间有两个代理服务器,客户端发送一个请求,服务器进行响应,期间报文流向为:客户端 -> 代理1 ->代理2 -> 服务器 -> 代理2 -> 代理1 -> 客户端。

报文的组成部分

每条报文都包含一条来自客户端的请求,或者来自服务器的响应。它们由三部分组成:对报文进行描述的起始行,包含属性的首部块,以及可选的、包含数据的主体部分。

起始行和首部是由行分隔的 ASCII 文本,每行的行终止符都由一个回车符和一个换行符组成,可书写成 CRLF。主体可以包含文本数据或二进制数据,也可以为空。

延伸:Unix 系统里,每行结尾只有“<换行>”,即“\n”;Windows系统里面,每行结尾是“ <回车><换 行>”,即“\r\n”;Mac系统里,每行结尾是“<回车>”。一个直接后果是,Unix/Mac系统下的文件在Windows里打 开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。

所有的 HTTP 报文都可以分为两类:请求报文和响应报文,两者的基本报文结构相同,具体内容有些许差别。

请求报文的格式如下:

<method> <request-URL> <version>    // 起始行
<headers> // 首部 <entity-body> // 主体

响应报文格式如下,

<version> <status> <reason-phrase>    // 起始行
<headers> // 首部 <entity-body> // 主体

下面对报文格式中的每一项进行概述性解释,

方法(method)

请求的起始行以方法作为开始,用来告诉服务器要做什么。比如 GET /test/index.text HTTP/1.1 , 方法是 GET,请求从服务器拿到 /test/idnex.text 文件内容。常用的 HTTP 方法有,

HTTP 方法 描述 是否包含请求主体
GET 安全方法,服务器向客户端发送命名资源
PUT 将来自客户端的数据存储到一个命名的服务器资源中去
POST 将客户端数据发送到一个服务器网关应用程序
DELETE 从服务器删除命名资源,客户端无法保证删除请求一定被执行,因为 HTTP 规范允许服务器在不通知客户端的情况下撤销请求
HEAD 安全方法,仅发送命名资源响应中的 HTTP 首部 ,用于在不获取实际资源的情况下对资源首部进行检查,判断某个对象是否存在,测试资源是否被修改
TRACE 对可能经过的代理服务器传送到服务器上去的报文进行追踪,用于查看原报文是否被更改过,或进行了何种更改
OPTIONS 决定可以在服务器上执行哪些方法

以上方法并不是所有浏览器都支持,也不是所有服务器都支持。安全方法指不会在服务器上执行任何内容变更并产生任何结果的方法。

虽然方法有这么多,但目前浏览器上的请求几乎被 GET 和 POST 包揽,这是为什么呢?下面有个非官方的网友回答,觉得解释得通不错,于是摘录,

按照定义,假设有资源组A,内部包含该1、2、3这些资源,则

获取资源A1:Get Url A1

新增资源A4:Post Url A + RAWDATA 4

修改资源A4:Put Url A + RAWDATA 4

删除资源A2:Delete Url A2

然而实际上多数人都这么做

获取资源A1:Get Url A1

新增资源A4:Post Url A + RAWDATA 4

修改资源A4:Post Url A4 + RAWDATA 4

删除资源A2:Get Url delete A1

即使是新浪的微博都 POST Url+access_token + RAWDATA empty 的方式使用。更多的人都在用 Get + delete 参数的方式来实现,不知道他们的理由是不知道、不理解、还是不愿意。

再者,网络环境恶劣,其实很多情况下我们网络的80端口是被劫持的么,而二级运营商则几乎100%都是被劫持的。某些设备劫持之后会代理你进行http访问,而这些设备是不认识其他请求方式的。代理不认识,就无法进行正常的识别和转发,这就导致其它协议无法正常使用。

某些二级运营商的劫持设备,Get、Post、Connection,如果遇到其他请求方式,就会返回你403错误或者500或者502。像现在有大量的跨域请求需要Option,遇到这种网络就完全报废了。本身这里就很不正常了,然而它返回的状态码也是错的,错误的请求方式,一般都是400、405等,但指责一个本身就不正常的设备有小毛病,是没有意义的。

(以上回答摘自:https://segmentfault.com/q/1010000007736404)

版本(version)

报文所使用的 HTTP 版本格式为 HTTP/<major>.<minor>,其中主要版本号(majoi) 和 次要版本号(minor)都是整数。版本号的说明是指应用程序支持的最高 HTTP 版本,而非明确的某一版本。与 HTTP 1.1 的应用程序进行通信的 HTTP 1.2 应用程序应该知道它不能支持任何 HTTP 1.2 的新特性,最多只能支持到 HTTP 1.1 的特性。

状态码(status)和原因短语(reason-phrase)

状态码和原因短语是服务器用来告诉客户端发生了什么的描述。原因短语 是 状态码 的可读版本,对人类阅读解释状态码有重要意义。比如:服务器返回状态码 304 Not Modified ,其中原因短语 Not Modified 就是对 状态码 304 的解释,可读性和可记忆性更强。

状态码位于响应报文的起始行中,通过三个数字代码对不同状态码进行分类,如下表,

整体范围 分类
100 ~ 199 信息提示, 如:101 Switching Protocols,说明服务器正在根据客户端的指定,将协议切换成 Update 首部所列的协议
200 ~ 299 成功,如: 200 OK,请求没问题,实体的主体部分包含了所请求的资源
300 ~ 399 重定向,如 301 Moved Permanently,请求的 URL 资源已被永久移除,响应头 location 首部应该包含资源现在的 URL;304 Not Modified,资源未更改,无需从服务器下载资源
400 ~ 499 客户端错误,如 404 Not Found,服务器无法找到所请求的 URL
500 ~ 599 服务器错误, 如 504 Gateway Timeout,响应来自网关或代理,在等待另一服务器时对请求进行响应超时了

缓存

200 ok / 200 from cache/ 200 from disk cache/ 304 not modified

首部(Headers)

通用首部

有些首部提供了与报文相关的最基本的信息,被称为通用首部。这些首部既可以用于请求报文,也可以用于响应报文。

首部 描述
Connection 允许客户端和服务器指定与请求/响应连接有关的数据。如, HTTP 1.0 需要保持客户端与服务器之间的连接,就要设置 Connection: keep-alive
Date 提供日期和时间标志,说明报文是什么时间创建的
Trailer 如果报文采用了分块传输代码方式,就可以用这个首部列出位于报文拖鞋部分的首部集合
Transfer-Encoding 告知接收端为了保证报文的可靠传输,对报文采用什么编码方式
Via 显示了报文经过的中间节点
Cache-control 用于随报文传送缓存指示,浏览器请求返回 304 状态码便和 Cache-control 息息相关

请求首部

请求首部是只在请求报文中有意义的首部。用于说明是谁或说明在发送请求、请求来自何处,或者客户端的喜好及能力。

首部 描述
User-agent 将发起请求的应用程序名称告知服务器,如: iMac 上使用 Chrome 发送请求, User-agent 可能就是 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
Accept 告诉服务器能够发送那些媒体类型
Accept-Encoding 告诉服务器能够发送哪些编码方式
Accept-Language 告诉服务器能够发送哪些自然语言
Cookie 客户端向服务器发送一个令牌。用户登录的实现基本上需要用到 Cookie ,设置好之后,由浏览器在每个请求后自动发送
Proxy-Connection 与 Connection 首部相同,但这个首部用在同哑代理(无法识别 connection: keep-alive 的代理)中使用

请求首部字段 Referer

一般Referer主要用于统计,像百度统计可以通过 Referer 统计访问流量的来源和搜索的关键词。Referer 是由浏览器自动加上的,刷新页面也不会消失,但某些情况不会发送 Referer 头部,如下:

● 直接输入网址或通过浏览器书签访问

● 来源页面采用的协议为表示本地文件的 "file" 或者 "data" URI

● 当前请求页面采用的是非安全协议,而来源页面采用的是安全协议 HTTPS(摘自 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Referer, 对此持有怀疑态度,验证未通过,验证结果详情参见下文)

通过 Google 搜索 “风铃” ,然后访问 zhan.qq.com ,可以看到请求头中包含 referer 头部,显示 https://www.google.com.hk/(风铃的域名是 zhan.qq.com), 如下图,

直接在浏览器中输入网址: zhan.qq.com 可以看到,请求头中并没有出现 referer 头部,如下图,

通过 file 协议地址跳转至目标网站 zhan.qq.com ,可以看到,请求头中依旧没有出现 referer 头部,如下图,

Google 安全协议 HTTPS 跳转至 智慧校园 非安全协议 HTTP 依旧有 referer 出现 ,与 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Referer 中描述的 “当前请求页面采用的是非安全协议,而来源页面采用的是安全协议 HTTPS ” 该情况不会产生 referer不一致,

响应首部

响应报文有自己的首部集,首部集为客户端提供一些额外的信息,比如 谁在发送响应、响应者的功能,甚至与响应相关的一些特殊指令。

首部 描述
Age 从最初创建开始响应持续时间
Server 服务器应用程序软件的名称和版本
Warning 比原因短语更详细一些的警告报文
Proxy-Authenticate 来自代理的对客户端的质询列表,指定了获取 proxy server(代理服务器)上的资源访问权限而采用的身份验证方式
www-Authenticate 来自服务器的对客户端的质询列表,使用这些验证方式去获取对资源的连接

实体的主体部分

实体首部提供了有关实体机器内容的大量信息,从有关对象类型的信息,到能够对资源使用的各种有效的请求方法。

首部 描述
Allow 列出了可以对此实体执行的请求方法
Location 告知客户端实体实际上位于何处,用于将接受端定位到资源的位置上去
Content-Length 主体的长度或尺寸
Content-MD5 主体的 MD5 校验和
Content-type 主体对象类型
ETag 某个特定资源的版本标识符, 服务器返回 304 状态码与其息息相关
Expires 实体不再有效,要从原始的源端再次获取此实体的日期和时间
Last-Modified 这个实体最后一次被修改的日期和时间

Cache-Control与Expires的作用一致,Last-Modified与ETag的作用也相近。Cache-Control 与 ETag 出现于较新的 HTTP/1.1 版本,优先级高于 Expires 和 Lat-Modified 。一般情况使用两对中的一对即可。Cache-Control 和 ETag 决定了 服务器是否返回 304 状态码, 详情请参考 http://mp.weixin.qq.com/s/k-ZtFUG674V0WAdQs3li8Q

如果想知道 请求结果 200 from cache, 304 的区别,具体可以参看: http://mp.weixin.qq.com/s/O6Ko7Sl3zsyzqGz9K_ORRw, 而两者最大的区别是 200 from cache 不会向服务器发送请求,而 304 会向服务器发送请求,只是不会下载资源文件。

下图是京东(www.jd.com)首页请求部分截图,出现了 200 from disk cache 和 200 from memory cache , 两者由之前的 from cache 演变而来,如果想知道二者的区别,请参看 https://www.quora.com/What-is-the-difference-between-memory-cache-and-disk-cache-in-Chrome, 大意是 内存 比 硬盘读取速度快很多,但内存会随着进程的关闭(浏览器的关闭)而清除,但硬盘上的则不会,所以浏览器会根据实际情况选择两种缓存方式,先从内存中读取资源,没有,再从硬盘读取,再没有,发送请求,此时服务器可能返回 304,也可能返回 200 OK,不会返回 200 from disk cache 或 200 from memory cache。


【参考内容】

《HTTP 权威指南》David Gourley 等编. 陈涓 赵振平译. 人民邮电出版社

https://bindog.github.io/blog/2014/11/18/http-referer-security-and-anti-anti-hotlink/](https://bindog.github.io/blog/2014/11/18/http-referer-security-and-anti-anti-hotlink/

【温故而知新】HTTP 报文的更多相关文章

  1. 温故而知新--day5

    温故而知新--day5 ip地址 IP是英文Internet Protocol的缩写,意思是"网络之间互连的协议",也就是为计算机网络相互连接进行通信而设计的协议.当多个设备要进行 ...

  2. 重温Http协议--请求报文和响应报文

    http协议是位于应用层的协议,我们在日常浏览网页比如在导航网站请求百度首页的时候,会先通过http协议把请求做一个类似于编码的工作,发送给百度的服务器,然后在百度服务器响应请求时把相应的内容再通过h ...

  3. Tcp/ip 报文解析

    在编写网络程序时,常使用TCP协议.那么一个tcp包到底由哪些东西构成的呢?其实一个TCP包,首先需要通过IP协议承载,而IP报文,又需要通过以太网传送.下面我们来看看几种协议头的构成 一 .Ethe ...

  4. 前端学HTTP之报文首部

    前面的话 首部和方法配合工作,共同决定了客户端和服务器能做什么事情.在请求和响应报文中都可以用首部来提供信息,有些首部是某种报文专用的,有些首部则更通用一些.本文将详细介绍HTTP报文中的首部 结构 ...

  5. [httpserver]如何解析HTTP请求报文

    这个http server的实现源代码我放在了我的github上,有兴趣的话可以点击查看哦. 在上一篇文章中,讲述了如何编写一个最简单的server,但该程序只是接受到请求之后马上返回响应,实在不能更 ...

  6. dhcp协议交互报文

    DHCP共有八种报文,分别为DHCP Discover.DHCP Offer.DHCP Request.DHCP ACK.DHCP NAK.DHCP Release.DHCP Decline.DHCP ...

  7. 前端学HTTP之报文起始行

    前面的话 如果说HTTP是因特网的信使,那么HTTP报文就是它用来搬东西的包裹了.HTTP报文是在HTTP应用程序之间发送的简单的格式化数据块,每条报文都包含一条来自客户端的请求,或者一条来自服务器的 ...

  8. DNS报文格式(RFC1035)

    一.域名和资源记录的定义 1.Name space definitions 2.资源记录定义(RR definitions)      2.1 格式          后面分析报文的时候详细解释.   ...

  9. Jmeter+TCP\Scoket(8583)报文压力测试

    Jmeter一般被用来测试HTTP协议,我第一次拿来测试socket协议,pos机传输报文为8583,协议属于socket,也是TCP协议的一种,网上有LR怎么测试8583报文,我就研究了一下怎么用J ...

随机推荐

  1. React中的通讯组件

    1.父传子:     传递:当子组件在父组件中当做标签使用的时候,给当前子组件绑定一个自定义属性,值为需要传递的数据     接收:在子组件内部通过this.props进行接收 2.子传父     传 ...

  2. hadoop退出安全模式Name node is in safe mode

    在使用 hdfs 的时候出现如下错误: 18/01/12 09:04:34 INFO fs.TrashPolicyDefault: Namenode trash configuration: Dele ...

  3. 从锅炉工到AI专家(5)

    图像识别基本原理 从上一篇开始,我们终于进入到了TensorFlow机器学习的世界.采用第一个分类算法进行手写数字识别得到了一个91%左右的识别率结果,进展可喜,但成绩尚不能令人满意. 结果不满意的原 ...

  4. Nginx+Tomcat搭建集群,Spring Session+Redis实现Session共享

    小伙伴们好久不见!最近略忙,博客写的有点少,嗯,要加把劲.OK,今天给大家带来一个JavaWeb中常用的架构搭建,即Nginx+Tomcat搭建服务集群,然后通过Spring Session+Redi ...

  5. 从0打卡leetcode之day 5 ---两个排序数组的中位数

    前言 我靠,才坚持了四天,就差点不想坚持了.不行啊,我得把leetcode上的题给刷完,不然怕是不好进入bat的大门. 题目描述 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 . ...

  6. C#2.0导航

    主要特性 泛型 类型和方法的参数化 可空类型 值类型可为null 委托 更简化的方式 迭代器 简单的foreach,不简单的状态机

  7. 全文检索-Elasticsearch (一) 安装与基础概念

    ElasticSearch是一个基于Lucene的搜索服务器.它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口 Elasticsearch由java开发,所以在搭建时,需先安 ...

  8. SVN就是这么简单

    什么是SVN SVN全称:Subversion,是一个开放源代码的版本控制系统 Svn是一种集中式文件版本管理系统.集中式代码管理的核心是服务器,所有开发者在开始新一天的工作之前必须从服务器获取代码, ...

  9. leetcode — pascals-triangle

    import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Source : https://o ...

  10. [一] java8 函数式编程入门 什么是函数式编程 函数接口概念 流和收集器基本概念

      本文是针对于java8引入函数式编程概念以及stream流相关的一些简单介绍 什么是函数式编程?   java程序员第一反应可能会理解成类的成员方法一类的东西 此处并不是这个含义,更接近是数学上的 ...