TCP/IP 协议族之应用层协议 ——HTTP

269 阅读15分钟

HTTP 历史

HTTP 全称“超文本传输协议”,英文名:"HyperText Transfer Protocol",是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。

说白了,就是约定的一组协议,设计之初就是用来发布和接收HTML页面的(HTTP/0.9)。

之后 HTTP “火遍全网”,更新升级之后(HTTP/1.0)更是牛逼了,什么内容都能传(这为互联网的大发展奠定了基础)。而且除了基本的 GET 命令外,新增了 POST ,HEAD 命令,这使得通过 HTTP 不仅能读取服务器的内容,还可以修改服务器上的内容!(下面详细介绍这些命令)。

正因为可以传输的东西多了,就需要标识传输内容的格式,所以 HTTP/1.0 请求响应的内容也不单单是数据部分。每次通信都必须包括头信息(HTTP header),用来描述一些元数据。其他的新增功能还包括状态码(status code)、多字符集支持、多部分发送(multi-part type)、权限(authorization)、缓存(cache)、内容编码(content encoding)等。

HTTP/1.0 虽然好,但是设计的时候是“无连接”的,即每个 TCP 连接只能发送一个请求。发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。

因为 TCP 连接的新建成本很高,因为需要客户端和服务器三次握手,并且开始时发送速率较慢(slow start)。所以,HTTP 1.0 版本的性能比较差。随着网页加载的外部资源越来越多,这个问题就愈发突出了。

伟大的事物之所以伟大,就是因为不断地迭代自身,1997年1月,HTTP/1.1 版本发布,只比 1.0 版本晚了半年。它进一步完善了 HTTP 协议,一直用到了20年后的今天,直到现在还是最流行的版本。

HTTP/1.1 版的最大变化,就是引入了持久连接(persistent connection),即TCP连接默认不关闭,可以被多个请求复用,不用声明Connection: keep-alive(浏览器默认给你加上)。

客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送Connection: close,明确要求服务器关闭 TCP 连接。

目前,对于同一个域名,大多数浏览器允许同时建立6个持久连接。

虽然HTTP/1.1 版还引入了管道机制(pipelining),即在同一个 TCP 连接里面,客户端可以同时发送多个请求。这样就进一步改进了 HTTP 协议的效率。但大部分浏览器都默认关闭这个功能(因为这个功能没有很好解决实际问题,并且还会带来性能问题)。

HTTP/2 基于谷歌实验项目 SPDY,于2015年5月正式成为标准。与 HTTP/1.1 相比,HTTP/2 的主要变化在于性能提升。相关技术关键词:二进制分帧层,数据流、消息和帧,请求与响应复用,数据流优先级,流控制,服务器推送,标头压缩这里就不做介绍(关于HTTP/2.0 详细信息可以查看 blog hpbn.co/http2/)

虽然HTTP/2 已经发布了一段时间,HTTP/3 也正在路上,但是目前为止,互联网使用最多,兼容范围最广的还是HTTP/1.1,如未特殊说明,以下内容基于 HTTP/1.1 版本进行描述。

浏览器发起 HTTP 请求流程

  1. 构建请求(构建请求行信息)
  2. 查找缓存(浏览器缓存是一种在本地保存的副本,以供下次请求时直接使用的技术,比如图片,脚本等静态资源)
  3. 准备 IP 地址和端口
  4. 等待 TCP 队列(同一个域名同时最多只能建立6个 TCP 连接,如果在同一个域名下同时有10个请求发生,那么其中就有4个请求进入排队等待状态。)
  5. 建立 TCP 连接
  6. 发送 HTTP 请求

请求和响应报文

  • 一行起始行用于描述要执行的请求,或者是对应的状态,成功或失败。这个起始行总是单行的。
  • 一个可选的 HTTP 头集合指明请求或描述消息正文。
  • 一个空行指示所有关于请求的元数据已经发送完毕。
  • 一个可选的包含请求相关数据的正文 (比如 HTML 表单内容), 或者响应相关的文档。 正文的大小有起始行的HTTP头来指定。
  • 起始行和 HTTP 消息中的 HTTP 头统称为请求头,而其有效负载被称为消息正文。

}

请求行

HTTP 请求是由客户端发出的消息,用来使服务器执行动作。起始行 (start-line) 包含三个元素:

一个 HTTP 方法,一个动词 (像 GET, PUT 或者 POST) 或者一个名词 (像 HEAD 或者 OPTIONS), 描述要执行的动作. 例如, GET 表示要获取资源,POST 表示向服务器推送数据 (创建或修改资源, 或者产生要返回的临时文件)。

请求目标 (request target),通常是一个 URL,或者是协议、端口和域名的绝对路径,通常以请求的环境为特征。请求的格式因不同的 HTTP 方法而异。它可以是:

一个绝对路径,末尾跟上一个 ' ? ' 和查询字符串。这是最常见的形式,称为 原始形式 (origin form),被 GET,POST,HEAD 和 OPTIONS 方法所使用。

POST / HTTP/1.1
GET /background.png HTTP/1.0
HEAD /test.html?query=alibaba HTTP/1.1
OPTIONS /anypage.html HTTP/1.0

一个完整的 URL,被称为 绝对形式 (absolute form),主要在使用 GET 方法连接到代理时使用。

GET http://developer.mozilla.org/en-US/docs/Web/HTTP/Messages HTTP/1.1

由域名和可选端口(以':'为前缀)组成的 URL 的 authority component,称为 authority form。 仅在使用 CONNECT 建立 HTTP 隧道时才使用。

CONNECT developer.mozilla.org:80 HTTP/1.1

星号形式 (asterisk form),一个简单的星号('*'),配合 OPTIONS 方法使用,代表整个服务器。

OPTIONS * HTTP/1.1

HTTP 版本 (HTTP version),定义了剩余报文的结构,作为对期望的响应版本的指示符。

请求头

来自请求的 HTTP headers 遵循和 HTTP header 相同的基本结构:不区分大小写的字符串,紧跟着的冒号 (':') 和一个结构取决于 header 的值。 整个 header(包括值)由一行组成,这一行可以相当长。

有许多请求头可用,它们可以分为几组:

General headers,例如 Via,适用于整个报文。

Request headers,例如 User-Agent,Accept-Type,通过进一步的定义(例如 Accept-Language),或者给定上下文(例如 Referer),或者进行有条件的限制 (例如 If-None) 来修改请求。

Entity headers,例如 Content-Length,适用于请求的 body。显然,如果请求中没有任何 body,则不会发送这样的头文件。

例子:

请求体

请求的最后一部分是它的 body。不是所有的请求都有一个 body:例如获取资源的请求,GET,HEAD,DELETE 和 OPTIONS,通常它们不需要 body。 有些请求将数据发送到服务器以便更新数据:常见的的情况是 POST 请求(包含 HTML 表单数据)。

请求体 大致可分为两类:

  1. Single-resource bodies,由一个单文件组成。该类型 body 由两个 header 定义: Content-Type 和 Content-Length.

  2. Multiple-resource bodies,由多部分 body 组成,每一部分包含不同的信息位。通常是和 HTML Forms 连系在一起。

常见请求方式

序号方法描述备注
1GET⭐请求指定的页面信息,并返回实体主体。幂等
2POST⭐向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改。非幂等
3PUT⭐从客户端向服务器传送的数据取代指定的文档的内容。幂等
4PATCH⭐是对 PUT 方法的补充,用来对已知资源进行局部更新 。非幂等
5DELETE⭐请求服务器删除指定的页面。幂等
6HEAD类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头幂等
7CONNECTHTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。非幂等
8OPTIONS允许客户端查看服务器的性能。幂等
9TRACE回显服务器收到的请求,主要用于测试或诊断。幂等

HTTP 的 GET,POST 请求方法区别

  1. GET 一般使用 Search 传参,POST 使用 Request Body 传参
  2. GET 方式 URL 有长度限制,一般为 2KB, POST 方式无长度限制
  3. GET 只需要一个报文,POST 需要两个以上
  4. GET 是幂等的, POST 不幂等
  5. 语义上 GET 是获取数据,POST 是提交数据

响应行

HTTP 响应的起始行被称作 状态行 (status line),包含以下信息:

协议版本,通常为 HTTP/1.1。 状态码 (status code),表明请求是成功或失败。常见的状态码是 200,404,或 302。 状态文本 (status text)。一个简短的,纯粹的信息,通过状态码的文本描述,帮助人们理解该 HTTP 消息。 一个典型的状态行看起来像这样:HTTP/1.1 404 Not Found。

响应头

响应的 HTTP headers 遵循和任何其它 header 相同的结构:不区分大小写的字符串,紧跟着的冒号 (':') 和一个结构取决于 header 类型的值。 整个 header(包括其值)表现为单行形式。

有许多响应头可用,这些响应头可以分为几组:

  1. General headers,例如 Via,适用于整个报文。

  2. Response headers,例如 Vary 和 Accept-Ranges,提供其它不符合状态行的关于服务器的信息。

  3. Entity headers,例如 Content-Length,适用于请求的 body。显然,如果请求中没有任何 body,则不会发送这样的头文件。

例子:

响应体

响应的最后一部分是 body。不是所有的响应都有 body:具有状态码 (如 201 或 204) 的响应,通常不会有 body。

响应体 大致可分为三类:

  1. Single-resource bodies,由已知长度的单个文件组成。该类型 body 由两个 header 定义:Content-Type 和 Content-Length。
  2. Single-resource bodies,由未知长度的单个文件组成,通过将 Transfer-Encoding 设置为 chunked 来使用 chunks 编码。
  3. Multiple-resource bodies,由多部分 body 组成,每部分包含不同的信息段。但这是比较少见的。

HTTP 响应状态码

规范规定 HTTP 的状态码为三位数,被分为五类:

分类分类描述
1**信息,服务器收到请求,需要请求者继续执行操作
2**成功,代表请求被服务器接收、理解、并接受
3**这类状态码代表需要客户端采取进一步的操作才能完成请求。通常,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的 Location 域中指明。
4**客户端错误,请求包含语法错误或无法完成请求
5**服务器错误,服务器在处理请求的过程中发生了错误

HTTP状态码列表

状态码状态码英文名称中文描述
100Continue继续。客户端应继续其请求
101Switching Protocols切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到 websocket 协议
200⭐OK请求成功。一般用于GET与POST请求
201Created已创建。成功请求并创建了新的资源
202Accepted已接受。已经接受请求,但未处理完成
203Non-Authoritative Information非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本
204⭐No Content无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
205Reset Content重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域
206⭐Partial Content部分内容。服务器成功处理了部分GET请求
300Multiple Choices多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择
301⭐Moved Permanently永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
302⭐Found临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
303⭐See Other查看其它地址。与301类似。使用GET和POST请求查看
304⭐Not Modified未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
305Use Proxy使用代理。所请求的资源必须通过代理访问
306Unused已经被废弃的HTTP状态码
307⭐Temporary Redirect临时重定向。与302类似。使用GET请求重定向
400⭐Bad Request客户端请求的语法错误,服务器无法理解
401⭐Unauthorized请求要求用户的身份认证
402Payment Required保留,将来使用
403⭐Forbidden服务器理解请求客户端的请求,但是拒绝执行此请求
404⭐Not Found服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
405Method Not Allowed所用的HTTP方法不在权限之内
406Not Acceptable服务器无法根据客户端请求的内容特性完成请求
407Proxy Authentication Required请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权
408Request Time-out服务器等待客户端发送的请求时间过长,超时
409Conflict服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突
410Gone客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置
411Length Required服务器无法处理客户端发送的不带Content-Length的请求信息
412Precondition Failed客户端请求信息的先决条件错误
413Request Entity Too Large由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息
414Request-URI Too Large请求的URI过长(URI通常为网址),服务器无法处理
415⭐Unsupported Media Type客户端要求返回的格式不支持比如JSON,服务器无法处理请求附带的媒体格式
416Requested range not satisfiable客户端请求的范围无效
417Expectation Failed服务器无法满足Expect的请求头信息
429Too Many Requests客户端的请求次数超过限额
500⭐Internal Server Error服务器内部错误,无法完成请求
501Not Implemented服务器不支持请求的功能,无法完成请求
502Bad Gateway作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
503⭐Service Unavailable由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
504Gateway Time-out充当网关或代理的服务器,未及时从远端服务器获取请求
505HTTP Version not supported服务器不支持请求的HTTP协议的版本,无法完成处理

HTTP 和 HTTPS 的区别

  1. HTTP 是超文本传输协议,信息是明文传输,HTTPS 则是具有安全性的TSL/SSL加密传输协议。
  2. HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443
  3. HTTP 的连接很简单,是无状态的。HTTPS 协议是由 TSL/SSL + HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。(无状态的意思是其数据包的发送、传输和接收都是相互独立的。无连接的意思是指通信双方都不长久的维持对方的任何信息。)