HTTP 协议即超文本传输协议 (HTTP-Hypertext transfer protocol),是互联网上应用最为广泛的一种网络协议,是一种详细规定了浏览器和万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。用于从 WWW 服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。

1. 概述

在 OSI 七层模型中,HTTP 协议位于最顶层的应用层中。通过浏览器访问网页就直接使用了 HTTP 协议。使用 HTTP 协议时,客户端首先与服务端的 80 端口建立一个 TCP 连接,然后在这个连接的基础上进行请求和应答,以及数据的交换。

HTTP 有两个常用版本,分别是 1.0 和 1.1。主要区别在于 HTTP 1.0 中每次请求和应答都会使用一个新的 TCP 连接,而从 HTTP 1.1 开始,运行在一个 TCP 连接上发送多个命令和应答。因此大幅度减少了 TCP 连接的建立和断开,提高了效率。


1.1. URI&URL

URL

统一资源定位符 URL(Uniform Resources Locator) 用来表示**资源在互联网上的位置和访问这些资源的方法**,并使每一个资源在整个互联网范围内具有唯一的标识符URL。即 URL 实际上就是资源在互联网上的地址

URI

统一资源标识符 URI(Uniform Recourses Identifier)就是由某个协议方案表示的资源定位标识符。协议方案是指访问资源所使用的协议类型名称。

  1. URI 强调的是给资源标记命名,URL 强调的是给资源定位

  2. URL 是 URI 的子集,所有的 URL 都是 URI,但不是每个 URI 都是 URL,还有可能是 URN。让 URI 能成为 URL 的当然就是那个 “访问机制,”网络位置”。

    e.g. http:// or ftp://

我们在浏览器输入的都是 URL,因为我们输入的目的是为了找到某一个资源


1.2.HTTP 的特点

  1. HTTP 使用了面向连接的 TCP 作为传输层协议,保证了数据的可靠传输。HTTP 客户首先发起一个与服务器的 TCP 连接,一旦连接建立。该浏览器和服务器进程就可以通过套接字接口访问 TCP。

  2. HTTP 协议本身是无连接的

    这就是说,虽然 HTTP 使用了 TCP 连接,但通信的双方在交换 HTTP 报文之间不需要先建立 HTTP 连接

  3. HTTP 协议是无状态的。无状态协议对于事务没有记忆能力,HTTP 服务器并不保存关于客户端的任何信息。同一个客户在短时间内两次请求同一个对象,服务器会对这两次请求作出两次响应,因为服务器并不记得曾经这个客户访问过,也不记得为这个客户服务器过多少次。

    [HTTP协议设计成无状态的原因]

    简化了服务器的设计,使服务器更容易支持大量并发的 HTTP 请求。

    有状态的协议更加复杂,需要维护客户端的状态,并且如果客户或服务器失效,会产生状态不一致,解决这种不一致的代价高。

    不需保存客户的状态信息可以减少服务器的 CPU 及内存的消耗。


  1. cookie 数据存放在客户的浏览器上,session 数据存放在服务器上
  2. cookie 不是很安全,别人可以分析存放在本地的 cookie 并进行 cookie 欺骗,所以将登陆信息等重要信息存放在 session 中比较好,其他信息如果需要保留,可以存放在 cookie 中
  3. session 会在一定时间内保存在服务器上,当访问增多,会比较占用服务器性能
  4. 单个 cookie 保存的数据不能超过4k,很多浏览器都限制一个站点最多保存20个 cookie
  5. http 协议是无状态的,但是很多应用需要服务器掌握客户端的状态,比如网上购物,这时 cookie 和session 就发挥了它们的作用

1.4.持续连接和非持续连接

HTTP 协议首先和服务器建立 TCP 连接。这需要三次握手,当建立 TCP 连接的三次报文握手的前两部分后(即经过了一个 RTT 时间后),客户将把 HTTP 请求报文作为建立TCP 连接的第三次握手的第三个报文的数据(前面介绍过三次握手中第三次握手客户端可以携带数据),发送给服务器。服务器收到 HTTP 请求报文后,就把所请求的文档作为响应报文返回给客户。

非连续连接是指当一系列请求到达服务器时,每个请求/响应应对是经过一个单独的 TCP 进行的。如果使用浏览器浏览一个页面,这个页面包含多个链接对象(如图片)那么就需要进行依次链接,每一次链接都导致 2× RTT 的开销。另一个开销就是服务器和客户每一次建立新的 TCP 连接都要分配缓存和变量。特别万维网服务器往往要同时服务器大量客户请求,所以非持续连接会使万维网服务器负担很重。

为了解决非连续连接的问题,HTTP 1.1 使用持续连接(默认),所谓的持续连接是指服务器在发送响应后仍然一段时间内保持这条连接,使同一个客户(浏览器)和该服务器可以继续在这条链接上传送后续的 HTTP 请求报文和响应报文。

持久连接的好处在于减少了 TCP 连接的重复建立和断开所造成的额外开销,减轻了服务器的负载。另外,减少开销的那部分时间,使 HTTP 请求和响应能更早的结束,这样Web页面的显示速度也就提高了。

HTTP/1.1协议的持续连接有两种工作方式,即非流水线方式(without pipelining)和流水线方式(with pipelining)。
非流水线方式的工作特点:客户在收到前一个响应后才能发出下一个请求。因此,在 TCP 连接已建立后,客户每访问一次对象都要用去一个往返时间 RTT。这比非持续连接要用去两倍 RTT 的开销,节省了建立 TCP 所需的一个 RTT 时间。上图的持续连接方式就是非流水线方式,这种方式的缺点是服务器在发送完一个对象后,其TCP 连接就处于空闲状态,浪费了服务器资源。

流水线方式的工作特点:客户在收到 HTTP 响应报文之前就能够接着发送新的请求报文。于是一个接着一个的请求报文到达服务器后,服务器就可以连续发回响应报文。因此,使用流水线方式时,客户访问所有的对象只需花费一个 RTT 时间。流水线工作方式使 TCP 连接中的空闲时间减少,提高了文档下载效率。

前面介绍,HTTP 是无状态协议,即 HTTP 协议自身不对请求和响应之间的通信状态进行保存。但是在狠多情况下需要保存用户状态,例如用户登录到一家购物网站,即使他跳转到该站的其他页面后,也需要能继续保持登录状态。针对这个实例,网站为了能够掌握是谁送出的请求,需要保存用户的状态。

为了解决上面的问题,目前大多站点使用 Cookie 技术。Cookie 是网站为了辨别用户身份,进行会话跟踪而存储在客户端上的数据。

当用户访问某个使用 Cookie 的网站时,该网站的服务器就为用户产生一个唯一的识别码,并以此作为索引在服务器的后端服务器数据库中产生一个表项。

服务器在给用户的 HTTP 响应报文中添加一个叫做 Set-Cookie 的首部行。如 Set-Cookie: 1234

当用户收到这个响应时,其浏览器就在它管理的特定的 Cookie 文件中添加一行,其中包括这个服务器主机名和 Set-Cookie 后面的给出的识别码。当用户继续浏览这个网站时,每发送一个 HTTP 请求报文,其浏览器就会从 Cookie 文件中取出这个网站的识别码,并放到 HTTP 请求报文的 Cookie 首部行中,即Coolkie: 1234

1.6. HTTP 断点续传

断点续传就是从文件上次中断的地方开始重新下载或上传,当下载或上传文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会去重头下载,这样很浪费时间。所以断点续传的功能就应运而生了。要实现断点续传的功能,需要客户端记录下当前的下载或上传进度,并在需要续传的时候通知服务端本次需要下载或上传的内容片段。

2. HTTP 报文格式

2.1. 请求报文格式

请求报文包含三部分:请求行、请求头部和请求正文三部分组成

  1. 请求行由3部分组成,分别为:请求方法、URL、协议版本。之间由空格分隔

    请求方法包括 GET,HEAD,PUT,POST,TRACE,OPTIONS,DELET以及扩展方法,当然并不是所有的服务器都实现了所有的方法,部分方法即便支持,处于安全性的考虑也是不可用的

  2. 请求头部

    HTTP 客户程序(例如浏览器),向服务器发送请求的时候必须指明请求类型(一般是 GET 或者 POST)。如有必要,客户程序还可以选择发送其他的请求头。对于 POST 请求来说 Content-Length 必须出现。

  3. 请求正文

2.2. 响应报文格式

HTTP 响应报文也由三部分组成:响应行、响应头、响应体

  1. 响应行

    响应行一般由协议版本、状态码及其描述组成

  2. 响应头

  3. 响应体

    响应体就是响应的消息体,如果是纯数据就是返回纯数据,如果请求的是HTML页面,那么返回的就是HTML代码,如果是 JS 就是 JS 代码等。

2.3. 请求方法

  1. POST:用于传输信息给服务器,主要功能与 Get 方法类似。
  2. GET 用于请求访问已经被 URL 识别的资源,可以通过 URL 传参给服务器。
  3. PUT:传输文件,报文主体包含文件内容,保存到对应 URL 位置。
  4. HEAD:获取报文首部,与 GET 方法类似,只是不返回报文主体,一般用于验证 URL 是否有效。
  5. DELET:删除文件,与 PUT 方法相反,删除对应 URL 位置的文件。
  6. OPTIONS: 返回服务器支持的 HTTP 方法。
  7. CONNECT: 把请求连接转换到透明的 TCP/IP 通道

2.4. 状态码

2.4.1. 2XX: 成功

  1. 200:请求被正常处理
  2. 204:请求被受理但没有资源可以返回
  3. 206:客户端只是请求资源的一部分,服务器只对请求的部分资源执行 GET 方法,相应报文中通过Content-Range 指定范围的资源。

2.4.2. 3XX: 重定向

HTTP重定向:服务器无法处理浏览器发送过来的请求,服务器告诉浏览器跳转到可以处理请求的url上。浏览器会自动访问该URL地址。

在 HTTP 协议中,重定向操作由服务器通过发送特殊的响应(即 redirects)而触发。HTTP 协议的重定向响应的状态码为 3xx 。浏览器在接收到重定向响应的时候,会采用该响应提供的新的 URL ,并立即进行加载;大多数情况下,除了会有一小部分性能损失之外,重定向操作对于用户来说是不可见的。

不同类型的重定向映射可以划分为三个类别:永久重定向、临时重定向和特殊重定向。

永久重定向

这种重定向操作是永久性的。它表示原 URL 不应再被使用,而应该优先选用新的 URL。搜索引擎机器人会在遇到该状态码时触发更新操作,在其索引库中修改与该资源相关的 URL。

编码 含义 处理方法 典型应用场景
301 Moved Permanently GET 方法不会发生变更,其他方法有可能会变更为 GET 方法,网站重构。
308 Permanent Redirect 方法和消息主体都不发生变化。 ***网站重构,用于非 GET 方法。

特殊重定向

除了上述两种常见的重定向之外,还有两种特殊的重定向。304(Not Modified,资源未被修改)会使页面跳转到本地陈旧的缓存版本当中(该缓存已过期(?)),而 300(Multiple Choice,多项选择) 则是一种手工重定向:以 Web 页面形式呈现在浏览器中的消息主体包含了一个可能的重定向链接的列表,用户可以从中进行选择。

编码 含义 典型应用场景
300 Multiple Choice 不会太多:所有的选项在消息主体的 HTML 页面中列出。也可以返回 200 OK 状态码。
304 Not Modified 缓存刷新:该状态码表示缓存值依然有效,可以使用。

2.4.3. 4XX:客户端错误

  1. 400:请求报文语法有误,服务器无法识别
  2. 401:请求需要认证
  3. 403:请求的对应资源禁止被访问
  4. 404:服务器无法找到对应资源
  5. 409(Conflict)表示请求的资源与资源的当前状态发生冲突
  6. 410(Gone)表示服务器上的某个资源被永久性的删除。

2.4.4. 5XX:服务器错误

  1. 500:服务器内部错误
  2. 503:服务器正忙
  3. 502: 表示错误网关,无效网关。
  4. 504: 表示网关超时,说明服务器作为网关或代理,但是没有及时从上游服务器收到请求。

3. 一次完整的 HTTP 请求所经历的7个步骤

当我们在web浏览器的地址栏中输入:www.baidu.com,具体发生了什么?

  1. www.baidu.com 这个网址进行 DNS 域名解析,得到对应的 IP 地址

    DNS 域名解析采用的是递归查询的方式

    • 首先会搜索浏览器自身的 DNS 缓存

    • 如果浏览器自身的缓存里面没有找到,那么浏览器会搜索系统自身的 Host 文件

      操作系统也会有一个域名解析的过程

      在 Windows 中可以通过C:\Windows\System32drivers\etc\hosts文件来设置,可以将任何域名解析到任何能够访问的IP地址。

      在 Linux 中这个配置文件是 /etc/hosts, 修改这个文件可以达到同样的目的。

      操作系统会在缓存中缓存这个解析结果

      如果在本机中仍然无法完成域名的解析,就会真正请求域名服务器来解析这个域名

    • 在网络配置中都会有 “DNS服务器地址” 这一项,这个地址就用于解决前面两个过程无法解析时要怎么办,操作系统会把这个域名发送给这里设置的 LDNS(Local DNS),也就是本地区的域名服务器。这个DNS 通常都提供给你本地互联网接入的一个 DNS 解析服务,例如你是在学校接入互联网,那么你的DNS服务器肯定在你的学校,如果你是在一个小区接入互联网的,那这个 DNS 就是提供给你接入互联网的应用提供商,即电信或者联通,也就是通常所说的SPA)

      转发模式

    • 如果 LDNS 仍然没有命中,就直接到 RootServer 域名服务器请求解析。

    • 根域名服务器返回给本地域名服务器一个所查询域的主域名服务器(gTLdServer)地址。

      gTLD是国际顶级域名服务器,如.com、 .cn、.org 等

    • 本地域名服务器(Local DNS Server) 再向上-步返回的主域名服务器发送请求

    • 接受请求的主域名服务器查找并返回此域名对应的 Name Server域名服务器的地址

      这个Name Server通常就是你注册的域名服务器,例如你在某个域名服务提供商申请的域名,那么这个域名解析任务就由这个域名提供商的服务器来完成。

    • NameServer 域名服务器会查询存储的域名和 IP 的映射关系表,在正常情况下都根据域名得到目标IP记录,连同一个 TTL 值返回给 DNS Server 域名服务器。

    • 返回该域名对应的 IP 和 TTL 值,Local DNS Server 会缓存这个域名和 IP 的对应关系,缓存的时间由 TTL 值控制。

    • 把解析的结果返回给用户,用户根据 TTL 值缓存在本地系统缓存中,城解析过程结束。

  2. 根据 IP,找到对应的服务器,发起 TCP 的三次握手

  3. 建立 TCP 连接后发起 HTTP 请求

    建立 TCP 连接之后,Web 浏览器就会向服务器发送请求命令。如:GET/hello/index.html HTTP/1.1。浏览器发送其请求命令之后,还要以头信息的形式向服务器发送一些别的信息(例:Accept ,User-Agent 等),之后浏览器发送一空白行来通知服务器,它已经结束了头信息的发送。

  4. 服务器响应 HTTP 请求

    浏览器向服务器发出请求后,服务器会浏览器进行应答,应答内容包括:协议的版本号和应答状态码 :HTTP/1.1 200 OK,响应头信息来记录服务器自己的数据,被请求的文档内容。最后发送一个空白行来表示头信息的发送到此为结束,接着以 Content-Type 响应头信息所描述的格式发送用户所请求的实际数据。

  5. 浏览器解析网页代码,并请求网页代码中的资源(如js、css、图片等)

    浏览器拿到 html 文件后,就开始解析其中的 html 代码,遇到js/css/image等静态资源时,就向服务器端去请求下载(会使用多线程下载,每个浏览器的线程数不一样),这是时候就用上 keep-alive特性了,建立一次HTTP连接,可以请求多个资源,下载资源的顺序就是按照代码里面的顺序,但是由于每个资源大小不一样,而浏览器又是多线程请求请求资源,所以这里显示的顺序并不一定是代码里面的顺序。

  6. 浏览器对页面进行渲染呈现给用户

  7. Web 服务器关闭 TCP 连接

    一般情况下,一旦 Web 服务器向浏览器发送了请求数据,它就要关闭 TCP 连接,然而如果浏览器或者服务器在其头信息加入了这行代码: Connection:keep-alive

    TCP连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。