HTTP协议之报文(二)

有一个经典的问题:在浏览器地址栏输入地址,然后回车,最后看见页面这个过程到底发生了什么?这个过程,用书面语来讲就是一个完整的浏览器事务。一个事务由一条请求命令(浏览器发往服务器)和一条响应结果(服务器发往浏览器)组成,而这种通信是通过HTTP报文进行的。学习HTTP,最基本的目标就是需要看懂HTTP报文。

<!--more-->

学习报文的时候,最好顺手打开一个网页(推荐Chorme浏览器),F12打开开发者工具,然后切换到Network面板,然后下方左侧Name列表随便选择一条,然后在右侧切换到Header面板,现在就可以愉快地学习啦。

1. 基本语法

HTTP报文是浏览器和服务器之间发送的数据块,一条报文可能是请求报文,也可能是响应报文,但是他们都由三部分组成:

  • 对报文进行描述的起始行
  • 包含属性的首部块
  • 可选的,包含数据的主体部分

下面是具体语法(从书上抄过来的):

// 请求报文
<method><request-URL><version>  // 起始行
<header>                         // 首部行
<entity-body>                    // 主体

// 响应报文
<version><status><reason-phrase>  // 起始行
<header>                         // 首部行
<entity-body>                    // 主体

2. 起始行

请求报文和响应报文最主要的结构区别在于起始行不一样:

  • 请求报文的首部行包含请求方法,资源URL和HTTP版本号
  • 响应报文包含HTTP版本号,请求资源的响应状态(一个三位数)和原因短语(一个英语短语文本)

2.1. HTTP版本号

在报文中提供版本号的目的是为了让使用HTTP的应用程序了解双方的的协议能力和报文格式:采用老版本的协议可能无法实现新版本协议的某些特性。HTTP从开始到现在的版本包括HTTP0.9,HTTP1.0,HTTP1.1(目前最常用),HTTP2.0(二十来年就这么几个版本,可见学习基础的东西是非常划算的)。另外,需要注意的是HTTP协议貌似是一个十分考虑向后兼容的协议

2.2. 资源URL

就是前面所提到的请求资源的路径。既然是请求报文,肯定是请求资源啦,不带上URL的话HTTP怎么知道把这个报文扔哪去

2.3. 请求方法

请求报文中的请求方法表明服务器针对该请求应当执行的操作,常见的请求方法有:

方法 描述
GET 从服务器获取一份文档
HEAD 只从服务器获取文档的首部
POST 向服务器发送需要处理的数据
PUT 将请求的主体放在服务器上
TRACE 追踪报文经过的代理服务器
OPTIONS 决定可以在服务器上执行哪些方法
DELETE 删除一份文档

最常用的方法大概就是GETPOST方法了。HTML文档中表单method属性的getpost,在数据传输过程中分别对应了HTTP协议中的GET和POST方法,区别在于:

  • 目的不同,Get是用来从服务器上获得数据,而Post是用来向服务器上传递数据。
  • 传递请求数据的方式不同,GET将参数添加在URL的查询字段后(URL位于请求报文的起始行),而POST将请求数据放在请求报文的主体部分
  • 由于浏览器可能缓存带有查询字段的URL,因此不能保证安全而被其他访问者查看;此外,某些浏览器对于URL的长度是有限制的,服务器一般也对URL长度有某些限制(超过会返回414错误,关于状态码马上就会讲到),因此在需要向服务器传递大量数据的时候一般使用POST方法

在工作中,GET方法可以应用在数据分页,跳转重定向等地方,而POST方法主要应用在账户登录,编辑信息提交等方面。 POST与GET的另外一个区别在于:GET方式请求的资源可以被缓存,而POST请求无法被缓存。缓存这个问题十分重要,咱们后面再详细了解。

2.4. 响应状态

状态码是一个三位数,第一位描述状态的一般类别(成功,失败...),后两位描述状态的详细信息,其中:

  • 1,表示信息提示
  • 2,表示请求成功,常见的状态码是200,对应的原因短语是OK
  • 3,表示重定向,要么告知客户端使用替代位置来访问他们感兴趣的资源,要么是服务器提供一个替代的响应而不是请求资源的内容。这在缓存中十分常见,常见的状态码是304 Not Modified,表示资源未修改,可直接使用缓存(缓存这个问题对于前端十分重要,后面会花很多时间来学习的)
  • 4,表示客户端错误,指浏览器发送了服务器无法处理的内容,比如最常见的404 Not Found表示服务器上不存在该资源
  • 5,表示服务端错误,有时候请求是有效的,服务端却出现错误,比如某段PHP漏了一个分号啥的,常见的是502 Bad Gateway表示无法连接

书中详细讲解了五类响应状态的完整状态码,就不搬过来了,这里是维基百科的链接,遇见不熟悉的状态码再回来查吧。

3. 首部行

起始行提供了整个报文的一个概览,在某些只需要了解报文的基本信息而不需要具体的资源信息(比如判断一个资源是否存在),我们可以使用HEAD方法发送请求,这个方法就只会返回报文的首部行。 因为起始行能够包含的信息太少了,在使用HEAD请求的时候会非常便捷。但是,在更多的时候,客户端和服务端都需要为报文提供更详细的信息。

首部行提供报文的额外描述信息,用来准确描述正在获取的资源、服务器或者客户端的行为。报文首部行由一组不区分大小写的属性名后跟一个冒号,再紧跟它的值(不必换行)的键值对组成,值前面的空格会被忽略掉。

有些首部信息是请求报文或响应报文专用的,有些首部则更通用一些。由于首部行的数量也比较多,因此下面只列举了一些经常遇见的首部行,这里是HTTP首部行字段的MDN文档。后面在学习HTTP连接,HTTP识别和认证,缓存等知识时,也会回过头来重新了解相关的首部行。

3.1. 通用首部

表示服务器和浏览器都可以使用的首部,又可以分为

  • 普通首部,提供与报文相关的最基本的信息,如Date,用来说明构建报文的时间和日期
  • 缓存首部,将资源缓存到本地副本,如Cache-Control, 特别指定缓存策略

3.2. 请求首部

请求报文独有的,为服务器提供关于请求数据的额外信息,又可以分为

  • Accept首部,将客户端的资源喜好和处理能力告知服务器,如Accept, 表示浏览器所希望接收的数据类型
  • 条件请求首部,为请求加上某些限制,如If-Modified-Since, 只有资源在指定事件后改变才发送该资源
  • 安全请求首部,允许客户端在请求资源之前先对自身进行认证,如Cookie, 用来帮助服务器识别客户端的身份
  • 代理请求首部,协助因特网代理更好地工作

3.3. 响应首部

响应报文独有的,向浏览器提供服务器的额外信息,又可以分为

  • 协商首部,为服务端和客户端对资源进行协商的能力,如Accept-Ranges,表示服务端对该资源可以接受的类型
  • 安全响应首部,是HTTP的质询/响应认证机制的响应侧,如Set-Cookie用于在客户端设置一个Cookie

3.4. 实体首部

可以用来说明实体主体及其内容部分的信息,又可以分为

  • 内容首部,表示实体内容的类型,尺寸以及处理它所需的其他有用信息,如Content-Length,表明响应主体的内容长度
  • 实体缓存首部,用于提供与被缓存实体有关的信息,如Expires, 用于指定了HTTP响应的过期时间

4. 实体

HTTP协议负责传送资源(只要声明了正确的URL),而报文的实体部分就是用来保存资源内容的。此外,HTTP还负责确保它的报文被正确传送,识别提取和适当处理,具体来说,HTTP需要确保他传送的资源满足下面的条件:

  • 可以被客户端正确识别(Content-typeContent-Language来表明资源类型和语言)以及正确地解包(Content-Length和Content-Encoding)
  • 是最新的(通过实体验证码和缓存过期限制),也是用户所需要的(通过内容协商)
  • 可以被快速传输(通过范围传输,差异编码和其他数据压缩方法),且完整到达,未被篡改(通过校验)

HTTP主要就是用来传送资源,上面列举了与资源传送相关的各种技术,每一项技术都很难直接通过简单地学习就能理解,关于主体部分,针对前端工作,我觉得应该首先应该掌握的是内容缓存,接下来的就让我们来弄个明白缓存到底是个什么鬼。

2018年五月面试发现的一些问题 BFC及其应用