Http入门葵花宝典

2,176 阅读38分钟
原文链接: github.com

@波比小金刚

如果觉得不错请扔个star过来。

如要转载,请注明出处。


[TOC]


1. web网络基础

1.1 HTTP概述

客户端通过一个URL向资源服务器请求资源并获取到资源,这一通信过程需要遵守HTTP协议,Web是建立在HTTP协议上通信的。

HTTP是 HyperText Transfer Protocol,译为超文本传输协议。

1.2 HTTP历史

1989年,欧洲核子研究组织的李博士提出了一种能让远隔两地的研究者们共享知识的设想。 基本理念是基于多种文本之间关联形成的超文本,连成可互相参阅的WWW(万维网)。

WWW 的主要构建技术:

  1. HTML
  2. HTTP
  3. URL

HTTP的版本:

  1. HTTP/0.9 1990年
  2. HTTP/1.0 1996年
  3. HTTP/1.1 1997年 目前主流的 HTTP 协议版本
  4. HTTP/2.0 指日可待

1.3 TCP/IP 协议族

HTTP属于TCP/IP协议族的一个子集。所以我们需要了解部分TCP/IP协议族的知识。 TCP/IP协议族是互联网相关的各类协议族的统称,包括HTTP协议、IP协议等。

1.3.1 TCP/IP协议族的分层管理

TCP/IP协议分层:

  1. 应用层

    应用层决定了向用户提供应用服务时通信的活动。

    TCP/IP 协议族内预存了各类通用的应用服务。比如,FTP(File Transfer Protocol,文件传输协议)和 DNS(Domain Name System,域 名系统)服务就是其中两类。

    HTTP 协议也处于该层。

  2. 传输层

    提供处于网络中两台计算机之间的数据传输。

    在传输层有两个性质不同的协议:TCP(Transmission Control Protocol,传输控制协议)和 UDP(User Data Protocol,用户数据报协议)。

  3. 网络层

    网络层用来处理在网络上流动的数据包。数据包是网络传输的最小数据单位。 网络层主要的作用就是在网络传输中确定一条路线。

  4. 链路层

    用来处理连接网络的硬件部分。包括控制操作系统、驱动、网卡等。

1.3.2 TCP/IP 通信传输流

部分图片看不见,请用chrome、opera等打开

这一过程大致就是在发送端按照应用层->传输层->网络层->链路层方向传递。 每一层都会增加一个该层的首部信息,然后在接收端是按照链路层->网络层->传输层->应用层的方向接收,每层都会把对应的首部去除。

这种把数据信息包装起来的做法称为封装。

1.3.3 IP协议、TCP协议、DNS协议

该层拥有和HTTP协议密不可分的IP协议、TCP协议、DNS协议。

  1. IP

    IP是一种协议,不要和IP地址搞混淆了。 IP协议位于网络层,其主要作用是保证数据包能够准确的送到对方。 而要保证准确送到,主要依靠的是 IP地址 和 MAC地址。

    IP 地址指明了节点被分配到的地址,MAC地址是指网卡所属的固定地址。 IP地址可以和MAC地址进行配对。IP地址可变换,但MAC地址基本上不会更改。

    ARP 协议凭借 MAC 地址进行通信: ARP 是一种用以解析地址的协议,根据通信方的IP地址就可以反查出对应的MAC地址。

    大致过程是发送端想要给一个IP地址发送数据,然后通过ARP协议解析出MAC地址。 然后通过路由机制中转,这个过程具体有多少个中转是无法预知的,最后成功送达。

  2. TCP 协议

    TCP协议位于传输层,提供可靠的字节流服务。

    字节流服务: 就是把大块的数据分割成报文段为单位的数据包进行管理。

    可靠的则是指的是TCP协议能够保证把数据准确的送到对方。 所以,TCP 协议为了更容易传送大数据才把数据分割,而且 TCP 协议能够 确认数据最终是否送达到对方。

    TCP用以保证数据准确送达的方式是采用了三次握手:

    发送端首先发送一个带 SYN 标志的数据包给对方。然后对方返回一个带 SYN/ACK 的数据包表示收到了。发送端再回一个带 ACK 的数据包表示握手结束。 如果这一过程在某一个阶段中断,TCP 协议会再次以相同的顺序发 送相同的数据包。

  3. DNS 服务

    提供域名到 IP 地址之间的解析服务。 因为较之于域名,IP地址更难记忆。DNS服务就诞生了,DNS服务可以通过域名推导出IP地址,当然,反过来通过IP地址解析出域名也是可以的。

1.3.4 一张图串联上述知识点

部分图片看不见,请用chrome、opera等打开

所以我们平时在浏览器地址栏输入一个地址,显示一个网页的过程大致如下:

发送端:

  1. 应用层:DNS登场,根据域名解析出IP地址
  2. 应用层:HTTP协议出场,生成一个HTTP请求报文
  3. 传输层:TCP协议登场,将数据分割并通过三次握手向目标传递
  4. 网络层:IP协议配合TCP协议,确定目的地,然后通过路由,一边路由一边传递数据包

接收端: 5. 网络层:数据送到 6. 传输层:TCP协议接收传递过来的数据包,并重组数据包。 7. 应用层:HTTP协议处理请求报文,生成响应报文。 8. 请求的结果再反向的一样的流程传回给发送端。

1.4 URL & URI

这是面试经常问到的一个问题,URL与URI的区别和联系(可能还会加上URN)。

1.4.1 URL

统一资源定位符,通常有三部分组成:

  1. 协议
  2. 存有该资源的主机IP地址(有时也包括端口号)
  3. 主机资源的具体地址。如目录和文件名等

每个资源文件有一个唯一的URL标识,还提供了操作、获取该资源的方法。或者这么说: 就是提供了一个唯一的路径去标识一个资源,并且还提供了操作、获取资源的方法。 简单来说就是不仅说明了 what the source is 还说明了 how to get it。

1.4.2 URI

统一资源标识符。

URI用字符串标识某一互联网资源,而URL表示资源的地点(互联 网上所处的位置)。可见URL是URI的子集。当然URN也是URI的子集。

URI仅仅只是说明了 what the source is。

2. 熟悉HTTP/1.1

HTTP/1.1(以下简称HTTP)是目前主流的HTTP协议版本。

2.1 熟悉报文结构

HTTP协议用于客户端和服务端之间的通信。请求一定由客户端发起,服务端做出响应。 这里发起的请求和响应都是以报文的形式。大家可以在控制台F12看到请求、响应报文。 这里先熟悉一下报文结构,后边会具体讲讲里面的内容。

  1. 请求报文

    一个简单的例子:

    POST /index.html HTTP/1.1         --对应--> 请求方式、请求URI、协议版本
    Host: hack.jp                     --对应--> 主机
    Connection: keep-alive            --对应--> 链接状态
    Content-Type: application/json    --对应--> 内容类型
    Content-Length: 16                --对应--> 内容长度
    ...
    
    name=tome&age=12                  --对应--> 内容实体
    

    提出代码:

    POST /index.html HTTP/1.1         --对应--> 请求方式、请求URI、协议版本
    Host: hack.jp                     --对应--> 主机
    

    根据这两行信息,可以获悉的URI完整表示应该是:hack.jp/index.html 如果要对服务器本身发起请求,可以把 请求URI 指定为 * 。

    POST * HTTP/1.1
    
  2. 响应报文

    一个简单的例子:

    HTTP/1.1 200 OK                       --对应-->协议版本、状态码、状态码原因短语
    Date: Tue, 10 Jul 2017 10:18:55 GMT   --对应-->日期 、响应首部字段
    Content-Length: 362
    Content-Type: text/html
    
    ...
    
    <html>                                 --对应--> 报文主体
    ...
    </html>
    

2.2 Cookie即将登场

这里说Cookie不合适,只是抛砖引玉。

HTTP是一种不保存状态,即无状态(stateless)协议。HTTP协议自身不对请求和响应之间的通信状态进行保存。也就是说在HTTP这个级别,协议对于发送过的请求或响应都不做持久化处理。

那就坑爹了不是,不能我登进一个网站,然后点了另一个页面就GG了是吧,所以引入了Cookie技术用来管理状态。

Cookie的知识在后边...在后边...在后边...

2.3 HTTP/1.1 中可使用的方法

  1. GET 获取资源

    GET 方法用来请求访问已被 URI 识别的资源。

  2. POST 传输实体主体

    POST 方法用来传输实体的主体。GET也可以干这活,具体就是GET & POST的区别了。

  3. PUT 传输文件

    PUT 方法用来传输文件。就像FTP协议的文件上传一样,要求在请求报文的主体中包含文件内容,然后保存到请求 URI 指定的位置。

    HTTP协议的PUT方法本身不带有验证机制,因此除了在REST结构的WEB网站中才有可能使用。响应的状态码如果是 204,表示的是发送成功,但是没有数据返回。

  4. HEAD 获得报文首部

    同GET一样,只是返回的东西不包括报文主体。

  5. DELETE 删除文件

    DELETE方法用来删除文件,是与PUT相反的方法。DELETE方法按请求URI删除指定的资源。

    HTTP协议的DELETE方法本身不带有验证机制,因此除了在REST结构的WEB网站中才有可能使用。响应的状态码如果是 204,表示的是发送成功,但是没有数据返回。

  6. OPTIONS 询问支持

    就是询问支持哪些方法,返回的是包含 Allow: GET,POST... 的报文

  7. TRACE 追踪路径

    通过该方法可以追踪请求是怎么一步一步被加工的,但是极其不安全。一般不用。

  8. CONNECT 隧道协议连接代理

    CONNECT方法要求在与代理服务器通信时建立隧道,实现用隧道协议进行TCP通信。主要使用 SSL(Secure Sockets Layer,安全套接 层和TLS(TransportLayerSecurity,传输层安全)协议把通信内容加密后经网络隧道传输。

    ...

2.4 Connection: keep-alive

这是HTTP/1.1提出的解决办法,解决的问题是TCP/IP多次链接关闭造成的开销。 如果没有持久链接,访问一个页面的时候,要请求图片、数据等资源,就会开闭多次TCP/IP协议,这样的开销是没有必要的,建立keep-alive的机制,保证了只需要建立一次TCP/IP链接,完成所有的请求。

持久连接使得多数请求以管线化(pipelining)方式发送成为可能。 管线化的方式让并行的请求得以实现,速度更快。

2.5 再说Cookie

Cookie技术的诞生是为了解决HTTP协议本身是无状态的问题。

Cookie 技术通过在请求和响应报文中写入 Cookie 信息来控制客户端的状态。

具体流程:

  1. 客户端发送一个请求

    GET /index.html HTTP/1.1
    Host: demo.jp
    
  2. 服务端响应的时候加入Set-Cookie,并记住这个cookie是给谁的

    HTTP/1.1 200 OK
    Date: 略
    Server: Apache
    <Set-Cookie: sid= 16516165165165;path="/"; expires=Wed, 10-Oct-12 07:12:20 GMT>
    
  3. 客服端再次发送请求的时候就会带上这个Cookie

    GET /index.html HTTP/1.1
    Host: demo.jp
    Cookie: sid= 16516165165165
    
  4. 服务端接收到后去对比Cookie,就会获取到之前的状态信息。

    Cookie的更多内容还是在后边...在后边...在后边...

3. HTTP报文详细解析

3.1 报文的结构

报文的结构大致分为首部、空行、主体三个部分。

报文首部中主要包含了请求行、状态行、请求首部字段、响应首部字段、实体首部字段、通用首部字段等。

3.2 提升传输的效率

通常,报文主体等于实体主体。只有当传输中进行编码操作时,实体主体的内容发生变化,才导致它和报文主体产生差异。

实体 = 实体首部 + 实体主体。

一下提升传输效率的编码均作用于实体。

  1. 内容编码

    内容编码指明应用在实体内容上的编码格式,并保持实体信息原样压缩。内容编码后的实体由客户端接收并负责解码。

    常用的内容编码有: gzip、compress等

  2. 分块传输编码

    在传输大容量数据时,通过把数据分割成多块(chunk),能够让浏览器逐步显示页面。

3.3 MIME

MIME(多用途因特网邮件拓展)的使用场景:我们可以发送不同数据类型的内容附件,但是邮件依然可以处理。它通过Multipart(多部分对象集合)来容纳不同类型的数据。

HTTP也有这样的机制。常见于文件、图片上传的场景。

我们常常使用的 Content-type 就是指定多部分对象集合对象的。包括:

  1. multipart/form-data

    上传表单文件的时候使用。

  2. multipart/byteranges

    状态码 206(Partial Content,部分内容)响应报文包含了多个范围的内容时使用。

    第1个类型很常用。就不赘述了,第2个常用于获取一部分访问范围数据或者多个范围的数据。简单举例就是,请求一个10000字节的图片文件,先获取图片的上半部分,再获取下半部。要和另一个首部字段 Content-Range 配合使用。

    Content-Range: bytes=5001-10000        // 5001-10000字节的内容
    Content-Range: bytes=5001-             // 5001字节以后的
    Content-Range: bytes=-3000, 5000-7000  // 从开始到3000字节以及5000-7000范围
    

3.4 内容协商

场景:访问Google中文版和英文版,浏览器设置中文或者英文。 然后访问同一个地址:www.google.com,就可以实现。这样的机制就叫做内容协商。

概念:内容协商机制是指客户端和服务器端就响应的资源内容进行交涉,然后提供给客户端最为适合的资源。内容协商会以响应资源的语言、字符集、编码方式等作为判断的基准

包含在请求报文中的某些首部字段(如下)就是判断的基准。比如 Accept等。后边在说..

内容协商的技术类型:

  1. 服务器驱动协商

    由服务器端进行内容协商。以请求的首部字段为参考,在服务器端自动处理。这样对用户不一定是最准确的。

  2. 客户端驱动协商

    由客户端进行内容协商的方式。用户从浏览器显示的可选项列表中手动选择。还可以通过JavaScript脚本自动的选择。

  3. 透明协商

    上述方式的结合体,服务端和客户端各自进行内容协商。

4. HTTP状态码

状态码的结构是:

200 OK

由一个三位数字的状态码 + 状态码原因短语组成。

大致分为5类:

  1. 1XX --> 接收的请求正在处理
  2. 2XX --> 请求正常处理完毕
  3. 3XX --> 需要进行附加操作以完成请求
  4. 4XX --> 服务器无法处理请求
  5. 5XX --> 服务器处理请求出错

4.1 常用状态码

状态码至少有60种以上,但是我们常用的就那么几种。

4.1.1 2XX 成功

  1. 200 OK

    这是最理想的结果。请求被正常、成功的处理了,你可以获得你想要的响应。

  2. 204 No Content

    表示请求发送成功,服务器也处理了,但是没有返回一个实体。适用于只想发送数据到服务端,而不需要返回什么资源的场景。

  3. 206 Partial Content

    针对某一范围的请求成功了,并可以GET到你想要的那部分Range的数据。也就是说响应报文中包含由 Content-Range 指定范围的实体内容。

4.1.2 3XX 重定向

  1. 301 Moved Permanently

    永久性的重定向。该状态码表示请求资源分配了新的URL,以后应该使用资源现在对应的URL了。

  2. 302 Found

    临时性重定向。该状态码表示请求的资源已被分配了新的URI,希望用户(本次)能使用新的URI访问。

  3. 303 See Other

    该状态码表示由于请求对应的资源存在着另一个URI,应使用GET方法定向获取请求的资源。303其实和302功能是一样的,但是303要求必须是GET请求。

  4. 304 Not Modified

    该状态码表示客户端发送附带条件的请求时,服务器端允许请求访问资源,但未满足条件的情况。304状态码返回时,不包含任何响应的主体部分。304虽然被划分在3XX 类别中,但是和重定向没有关系。

    附带条件的请求是指采用GET方法的请求报文中包含If-Match,If-ModifiedSince,If-None-Match,If-Range,If-Unmodified-Since 中任一首部。

  5. 307 Temporary Redirect

    临时重定向,与302也是差别不多的。主要是限制了POST请求变为GET请求。

4.1.3 4XX 客户端错误

出现4XX的状态码说明了错误是发生在客户端。

  1. 400 Bad Request

    该状态码表示请求报文中存在语法错误。你能做的就是check你的请求内容,然后重新发送。

  2. 401 Unauthorized

    该状态码表示发送的请求需要有通过HTTP认证(BASIC认证、DIGEST认证)的认证信息。服务端会返回两次401响应,第一次对应会弹出一个对话框让你填写用户名、密码啥的认证信息,第二次返回401就是表示 bad credentials,你GG了,认证失败。

  3. 403 Forbidden

    该状态码表明对请求资源的访问被服务器丑拒了。这还是挺常见的,跨域不就是!

  4. 404 Not Found

    该状态码表明服务器上无法找到请求的资源。仔细看看你的地址之类的...

4.1.4 5XX 服务端错误

5XX 的响应结果表明服务器本身发生错误

  1. 500 Internal Server Error

    该状态码表明服务器端在执行请求时发生了错误,后台的服务可能出现了Bug。

  2. 503 Service Unavailable

    该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。 这样对客户端有点不友好,最好加入一个RetryAfter首部字段信息,告诉客户端什么时候能调用。

状态码是我们调试程序很依靠的凭据,但是也不能全信,坑爹的是有时候web内部发生了错误,也有可能返回200 OK。你能怎么办呢。哎~

5. Web服务器

一台服务器可以搭建多个Web站点。因为有虚拟主机的技术,即使物理层面只有一台服务器,你也要当成是有多台服务器。

前边提到了在应用层DNS服务会解析域名为IP地址,再发送请求,所以同一台服务器如果接受到两个不同的站点发来的请求,其IP地址是一致的,为了加以区别就必须在请求信息中加上域名URI。

5.1 代理、网关、隧道

代理、网关、隧道都属于通信数据转发程序,它们可以配合服务器将请求转发给下一站的服务器,并能够接收那台服务器返回的响应信息,然后转发给客户端。

  1. 代理

    代理是一种具有转发功能的应用程序。它类似于服务器和客户端之间的中间人,能够接收客户端的请求并转发给服务端,并且接受服务端响应,转发给客户端。

    客户端和服务器之间可以途径多个代理服务器,每次经过一个代理服务器比如Proxy1,都会在请求的首部添加一个Via首部信息:Via: Proxy1。

    代理一般分为缓存代理和透明代理/非透明代理。缓存代理指代理服务器会缓存服务器返回的响应资源,再次接收到对相同资源的请求时,就可以不从源服务器那里获取资源,而是将之前缓存的资源作为响应返回。透明和非透明则是指对报文是否进行了加工。

    缓存资源可以存在缓存服务器也可以存在浏览器(本地)。会向服务器去确认缓存的有效性,并及时更新资源。

  2. 网关

    网关是转发其他服务器通信数据的服务器,接收从客户端发送来的请求时,它就像自己拥有资源的源服务器一样对请求进行处理。有时客户端可能都不会察觉,自己的通信目标是一个网关。

    网关服务器和代理服务器类似,但是网关服务器可以接受客户端HTTP请求,然后向资源服务器发起一个非HTTP请求,然后获取非HTTP响应,再返回一个HTTP响应给客户端。

    利用网关能提高通信的安全性。因为可以在客户端与网关之间的通信线路上加密以确保连接的安全。

  3. 隧道

    隧道可按要求建立起一条与其他服务器的通信线路,届时使用SSL等加密手段进行通信。隧道的目的是确保客户端能与服务器进行安全的通信。

    隧道本身不会去解析 HTTP 请求。也就是说,请求保持原样中转给之后的服务器。隧道会在通信双方断开连接时结束。

6. HTTP 首部

HTTP 首部字段是构成 HTTP 报文的要素之一。在客户端与服务器之间以HTTP协议进行通信的过程中,无论是请求还是响应都会使用首部字段,它能起到传递额外重要信息的作用。 使用首部字段是为了给浏览器和服务器提供报文主体大小、所使用的语言、认证信息等内容。

  1. 请求报文

    请求报文包括请求行(请求方法+URI+协议版本)、请求首部字段、通用首部字段、实体首部字段。

    GET / HTTP/1.1 
    Host: hackr.jp 
    User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0 
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*; q=0.8 Accept-Language: ja,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip, deflate DNT: 1 
    Connection: keep-alive 
    If-Modified-Since: Fri, 31 Aug 2007 02:02:20 GMT 
    If-None-Match: "45bae1-16a-46d776ac" 
    Cache-Control: max-age=
    
  2. 响应报文

    响应报文包括状态行(协议+状态码+原因短语)、响应首部字段、通用首部字段、实体首部字段。

    HTTP/1.1 304 Not Modified Date: 
    Thu, 07 Jun 2012 07:21:36 GMT 
    Server: Apache 
    Connection: close 
    Etag: "45bae1-16a-46d776ac"
    

6.1 4中首部字段

首部字段包括一下四种:(图片看不见就用chrome、opera,反正不要用IE)

  1. 通用首部字段

  2. 请求首部字段

  3. 响应首部字段

  4. 实体首部字段

实际不止这些首部,一些非HTTP的首部字段也很常用,比如Cookie、Set-Cookie等。

语法:首部字段名:指令(参数)

6.2 部分通用首部及其指令解析

  1. Cache-Control

    通过指定首部字段 Cache-Control 的指令,就能操作缓存的工作机制。

    eg:

    Cache-Control: private, max-age=0, no-cache
    

    指令:

    1. public | private

      两个都是响应报文中的指令,public表示其他人也可以利用缓存,private与之相反,表示特定的人才可以。

    2. no-cache

      如果是请求报文中有该指令,表示客户端将不会接收缓存过的响应。从而保证不会获取到过期的资源。源服务器也不会对缓存服务器发出的资源有效性进行确认。

      如果是响应中有这个指令,表示缓存服务器不能直接缓存客户端请求的资源。同时响应中的no-cache可以有参数。如果没参数客户端是可以缓存对应的响应资源的,如果有参数,那么指定该参数的响应报文对应的响应资源不能被客户端缓存。

      Cache-Control: no-cache=Location
      
    3. no-store

      注意同 no-cache 的区别。该指令规定缓存不能在本地存储请求或响应的任一部分。no-cache准确的说是表示不缓存过期的资源,因为no-cache表示缓存服务器必须向源服务器发起一个资源有效性确认,然后才会处理资源。所以说no-store 才是真正地不进行缓存

    4. max-age

      Cache-Control: max-age=604800(单位:秒)
      

      当客户端发送的请求中包含 max-age 指令时,如果判定缓存资源的缓存时间数值比指定时间的数值更小,那么客户端就接收缓存的资源。另外,当指定max-age 值为0,那么缓存服务器通常需要将请求转发给源服务器。

      当服务器返回的响应中包含max-age指令时,缓存服务器将不对资源的有效性再作确认,而 max-age 数值代表资源保存为缓存的最长时间。

    5. s-maxage

      s-maxage 指令的功能和max-age指令的相同,s-maxage指令只适用于供多位用户使用的公共缓存服务器(一般就是代理)。不同点就是对于向同一用户重复返回响应的服务器来说,这个指令没有任何作用。

    6. min-fresh

      Cache-Control: min-fresh=60(单位:秒)
      

      要求缓存服务器返回至少还未过指定时间的缓存资源。

    7. max-stale

      Cache-Control: max-stale=3600(单位:秒)
      

      对应的值为过期有效时间,也就是说哪怕是过期的缓存资源,只要时间没有超过3600秒,也会被返回。

    8. only-if-cached

      Cache-Control: only-if-cached
      

      表示客户端仅在缓存服务器本地缓存目标资源的情况下才会要求其返回。如果没有,就返回504 Gateway Timeout

    9. must-revalidate

      Cache-Control: must-revalidate
      

      代理会向源服务器再次验证即将返回的响应缓存目前是否仍然有效。若代理无法连通源服务器再次获取有效资源的话,缓存必须给客户端一条504(GatewayTimeout)状态码。

      另外,使用must-revalidate指令会忽略请求的max-stale指令(即使已经在首部使用了 max-stale,也不会再有效果。

    10. proxy-revalidate

      Cache-Control: proxy-revalidate
      

      要求所有的缓存服务器在接收到客户端带有该指令的请求返回响应之前,必须再次验证缓存的有效性

    11. no-transform

      Cache-Control: no-transform
      

      使用no-transform指令规定无论是在请求还是响应中,缓存都不能改变实体主体的媒体类型。

      这样做可防止缓存或代理压缩图片等类似操作。

    总结如下:

    请求中含有cache-control指令:

    响应中含有cache-control指令:

  2. Connection

    Connection首部作用:

    1. 控制不再转发给代理的首部字段

      GET / HTTP/1.1
      Upgrade: HTTP/1.1
      Connection: Upgrade
      

      比如上面的报文中Connection的作用就是告诉代理服务器转发这个请求的时候把Upgrade首部删除了再发送。

      所以代理转发给源服务器的报文就会是:

      GET / HTTP/1.1
      
    2. 管理持久连接

      HTTP/1.1版本的连接默认都是持久连接,客户端得以在一个持久连接上可以连续发送请求,但是服务器想断开也可以,指定:

      Connection: Close
      

      HTTP1.1之前的连接不是默认持久连接的。如果要想是持久连接就需要指定:

      Connection: Keep-Alive
      
  3. Date

    表明创建 HTTP 报文的日期和时间。

  4. Pragma

    是 HTTP/1.1 之前版本的历史遗留字段,仅作为与 HTTP/1.0 的向后兼容而定义。

    规范定义的形式唯一:

    Pragma: no-cache
    

    因为在请求在各种中间服务器之间转发,想要所有的服务器都是HTTP1.1版本的是不现实的,所以为了实现兼容一般是这样的:

    Cache-Control: no-cache
    Pragma: no-cache
    
  5. Trailer

    告诉服务器在报文主体后面还记录了哪些首部字段。

    HTTP/1.1 200 OK 
    Date: Tue, 03 Jul 2012 04:40:56 GMT 
    Content-Type: text/html
    Transfer-Encoding: chunked 
    Trailer: Expires 
    
    ...(报文主体)... 
    0 
    Expires: Tue, 28 Sep 2004 23:59:59 GMT 
    

    这里的0表示分块长度。

  6. Transfer-Encoding

    规定了传输报文主体时采用的编码方式。

    Transfer-Encoding: chunked 
    

    响应报文如果有上边的首部并且值为chunked,表示报文主体会被分块传输。

  7. Upgrade

    Upgrade 用于检测 HTTP 协议及其他协议是否可使用更高的版本进行通信,其参数值可以用来指定一个完全不同的通信协议

    使用首部字段 Upgrade 时,还需要额外指定 Connection:Upgrade。

  8. Via

    追踪客户端与服务器之间的请求和响应报文的传输路径。

    每经过一个代理服务器都会往Via首部记录下该服务器的信息。

    Via 首部是为了追踪传输路径,所以经常会和TRACE方法一起使用。比如,代理服务器接收到由 TRACE 方法发送过来的请求(其中Max-Forwards:0)时,代理服务器就不能再转发该请求了。这种情况下,代理服务器会将自身的信息附加到Via首部后,返回该请求的响应。

  9. Warning

    该首部通常会告知用户一些与缓存相关的问题的警告。

    Warning: [警告码][警告的主机:端口号]“[警告内容]”([日期时间])
    

6.3 部分请求首部及其指令解析

  1. Accept

    Accept首部字段可通知服务器,用户代理能够处理的媒体类型及媒体类型的相对优先级。

    简单的说就是告诉服务器我要什么类型的数据。可以同时指定多种格式的类型,比如

    Accept: image/jpeg, image/gif, image/png;q=1.0
    

    上面的意思就是我接收图片类型数据,jpeg,gif,png都可以,但是png类型的优先级最高。这里的 ;q= 表示的是权重值,介于0-1之间,用 ; 和类型隔开。越大优先级越高。

  2. Accept-Charset

    Accept-Charset首部字段可用来通知服务器用户代理支持的字符集及字符集的相对优先顺序。可一次性指定多种字符集,也有优先级配置 q

    Accept-Charset: iso-8859-5, unicode-1-1;q=0.8
    
  3. Accept-Encoding

    用来告知服务器用户代理支持的内容编码及内容编码的优先级顺序。可一次性指定多种内容编码。

    Accept-Encoding: gzip, deflate
    

    采用权重 q 值来表示相对优先级,这点与首部字段Accept相同。另外,也可使用星号(*)作为通配符,指定任意的编码格式。

    常用编码类型:

    1. gzip: 文件压缩程序 gzip(GNU zip)生成的编码格式
    2. compress: UNIX 文件压缩程序 compress 生成的编码格式
    3. deflate: deflate 压缩算法 (RFC1951)生成的编码格式
    4. identity: 不执行压缩或不会变化的默认编码格式
  4. Accept-Language

    Accept-Language: zh-cn,zh;q=0.7,en-us,en;q=0.3
    

    告知服务器用户代理能够处理的那种语言,也可以指定多种,通过q来配置优先级。

  5. Authorization

    告诉服务器的用户代理的认证信息。

    通常是这样的过程:

    第一步: 发送一个请求

    GET /index.html HTTP/1.1
    

    第二步: 接受到一个401的响应,提示输入验证信息,比如用户名和密码或者直接输入一个什么token。

    Unauthorized 
    WWW-Authorized: Basic ...
    

    第三步:

    GET /index.html HTTP/1.1
    Authorization: Basic asdaf1651651=== ...
    
  6. Expect

    Expect: 100-continue
    

    客户端告知服务端希望的行为。

  7. From

    首部字段 From 用来告知服务器使用用户代理的用户的电子邮件地址。

  8. Host

    首部字段 Host 会告知服务器,请求的资源所处的互联网主机名和端口号。因为同一IP地址下部署了多个域名的虚拟主机的话,服务器不知道请求的是哪一个,就需要通过Host首部字段明确指出请求的主机名。

    Host是请求报文中唯一要求必须要有的首部字段。若服务器未设定主机名,那直接发送一个空值即可。

  9. If-Match

    只有当 If-Match 的字段值跟 ETag 值匹配一致时,服务器才会接受请求。 实体标记(ETag)是与特定资源关联的确定值,资源更新后Etag也会更新。

    还可以使用星号(*)指定 If-Match 的字段值。针对这种情况,服务 器将会忽略 ETag 的值,只要资源存在就处理请求

  10. If-Modified-Since

    如果在If-Modified-Since字段指定的日期时间后,资源发生了更新,服务器会接受请求。否则返回304 Not Modified

    If-Modified-Since 用于确认代理或客户端拥有的本地资源的有效性。获取资源的更新日期时间,可通过确认首部字段 Last-Modified 来确定。

  11. If-None-Match

    只有在 If-None-Match 的字段值与 ETag 值不一致时,可处理该请求。与If-Match 首部字段的作用相反。

    在 GET 或 HEAD 方法中使用首部字段 If-None-Match 可获取最新的资源。

  12. If-Range

    它告知服务器若指定的 IfRange 字段值(ETag 值或者时间)和请求资源的 ETag 值或时间相一致时,则作为范围请求处理。反之,则返回全体资源。

  13. If-Unmodified-Since

    和首部字段 If-Modified-Since的作用相反。它的作用的是告知服务器,指定的请求资源只有在字段值内指定的日期时间之后,未发生更新的情况下,才能处理请求

  14. Max-Forwards

    Max-Forwards: 10
    

    在代理服务器间转发一次这个数值就会减去1,服务器接收到 Max-Forwards值为 0 的请求时,就不再转发了,就会发起响应。

  15. Range

    Range: bytes=5001-10000
    

    对于只需获取部分资源的范围请求,包含首部字段Range即可告知服务器资源的指定范围。上面的示例表示请求获取从第 5001 字节至第 10000 字节的资源。

    接收到附带Range首部字段请求的服务器,会在处理请求后返回状态码为206Partial Content 的响应。无法处理该范围请求时,则会返回状态码200OK的响应及全部资源。

  16. Referer

    首部字段 Referer 会告知服务器请求的原始资源的 URI。 就是说查看这个首部就知道请求是哪个页面发起的。

  17. User-Agent

    首部字段 User-Agent 会将创建请求的浏览器和用户代理名称等信息传达给服务器。 爬虫作者也可能会把自己的邮箱加入到这个首部字段中。

6.4 部分响应首部及其指令解析

  1. Accept-Ranges

    只有两种:

    Accept-Ranges: none // 告知客户端,服务器不能处理范围请求
    Accept-Ranges: byte // 告知客户端,服务器可以处理范围请求
    
  2. Age

    Age: 600
    

    告诉客户端,源服务器在多久之前创建了响应。

    如果是缓存服务器发起响应,该值表示的是缓存资源向源服务器发起资源认证到认证完成的时间。直白的说就是,10分钟前我刚跟源服务器确认过资源。

  3. ETag

    ETag: "82e22293907ce725faf67773957acd12"
    

    ETag表示实体表示,是服务器分配给资源的字符串形式的唯一标识。资源更新的同时ETag也会更新。

    强ETag值:

    无论发生多么细微的变化,都会更新值。

    弱ETag值:

    弱 ETag 值只用于提示资源是否相同。 前边有个 W 表示。只有资源发生了根本改变,产生差异时才会改变 ETag 值。

  4. Location

    Location: http://www.usagidesign.jp/sample.html
    

    基本上,该字段会配合 3xx :Redirection 的响应,提供重定向的 URI

  5. Retry-After

    Retry-After: 120
    

    首部字段Retry-After告知客户端应该在多久之后再次发送请求。主要配合状态码503 Service Unavailable 响应,或 3xx Redirect 响应一起使用

  6. Server

    Server: Apache/2.2.17 (Unix)
    

    首部字段 Server 告知客户端当前服务器上安装的 HTTP 服务器应用程序的信息

  7. Vary

    Vary: Accept-Language
    

    从代理服务器接收到源服务器返回包含Vary指定项的响应之后,若再要进行缓存,仅对请求中含有相同 Vary 指定首部字段的请求返回缓存。

  8. WWW-Authenticate

    WWW-Authenticate: Basic realm="Usagidesign Auth"
    

    用于HTTP访问认证。它会告知客户端适用于访问请求URI所指定资源的认证方案(Basic 或是 Digest)和 带参数提示的质询(challenge)。

    状态码 401 Unauthorized 响应中, 肯定带有首部字段 WWW-Authenticate

6.5 部分实体首部及其指令解析

  1. Allow

    Allow: GET, HEAD
    

    告诉客户端支持的HTTP方法。

  2. Content-Encoding

    Content-Encoding: gzip
    

    告诉客户端返回的实体的编码方式,其实就是压缩的方式。

  3. Content-Language

    Content-Language: zh-C
    

    告诉客户端实体使用的啥语言

  4. Content-Length

    Content-Length: 15000
    

    告诉客户端返回的实体的主体大小,单位是byte。

  5. Content-Location

    Content-Location: http://www.hackr.jp/index-ja.html
    

    报文主体部分相对应的 URI

  6. Content-MD5

    Content-MD5: OGFkZDUwNGVhNGY3N2MxMDIwZmQ4NTBmY2IyTY==
    

    客户端采用同样的算法,然后与之比较,从而确定资源的有效性和完整性。

  7. Content-Range

    Content-Range: bytes 5001-10000/1000
    

    告诉客户端返回的实体范围。用于范围请求。

  8. Content-Type

    Content-Type: text/html; charset=UTF-8
    

    实体主体内对象的媒体类型。

  9. Expires

    Expires: Wed, 04 Jul 2012 08:26:05 GM
    

    告诉客户端资源失效的日期。

  10. Last-Modified

    Last-Modified: Wed, 23 May 2012 09:59:55 GMT
    

    资源最终修改的时间。

6.6 与Cookie有关的首部及其指令解析

  1. Set-Cookie 响应首部字段

    Set-Cookie: status=enable; expires=Tue, 05 Jul 2011 07:26:31
    

    当服务器准备开始管理客户端的状态时,会事先告知各种信息。

    Set-Cookie 的字段值: 1. expires 指定浏览器可发送 Cookie 的有效期。 2. path 限制指定 Cookie 的发送范围的文件目录 3. domain 指定domain:example.com,结尾是example.com都可以发送cookie。类似模糊匹配。 4. secure 限制 Web 页面仅在 HTTPS 安全连接时,才可以发送 Cookie 5. HttpOnly 防止 XSS

  2. Cookie 请求首部字段

    Cookie: status=enable
    

    当客户端想获得 HTTP 状态管理支 持时,就会在请求中包含从服务器接收到的 Cookie。

7. HTTPS

HTTP有三个很大的隐患:

  1. 通信使用明文(不加密),内容可能会被窃听
  2. 不验证通信方的身份,因此有可能遭遇伪装
  3. 无法证明报文的完整性,所以有可能已遭篡改(中间人攻击)

HTTPS可以解决上面的问题:

  1. 对通信或者通信内容进行加密

    由于HTTP本身是不具备加密的能力的,所以,所有的报文都是明文(未加密)发送的。使用抓包工具可以一览无余,这个时候解决办法通常有两类:

    1. 通信加密,通过与SSL或TLS组合使用,实现通信在一个安全的线路进行。
    2. 内容加密,就是将报文的主体加密,但是该方式仍然有内容被篡改的风险。

    TLS是基于SSL3.0制定的,所以某种意义上可以统称为SSL。

  2. 通过证书或者别的方式验证通信方的身份

    HTTP 协议中的请求和响应不会对通信方进行确认。简单说就是任何人都可以发起请求,而服务器对每个请求都会有一个响应,来者不拒。

    这样导致无法确定客户端就是那个"客户端",服务器就是那个"服务器",亦或者是客户端、服务器都对的上,但是操作的人是没权限的等情况。

    解决的办法就是使用证书,证书是第三方机构颁发的,用来双向的进行身份验证。

  3. 保证内容的完整性

    请求或响应在传输途中,遭攻击者拦截并篡改内容的攻击称为中间人攻击。 HTTP可以通过比如MD5、SHA-1等散列值校验,或者是数字签名的方法确保数据的完整性,但是这些都需要用户本人来操作,浏览器是不能帮着用户完成检查的。而且也不是百分百的安全,在网络世界里,没有绝对的安全。

    HTTP可以和SSL组合提完整性数据保护。

综述我们总结出HTTPS的结构:

HTTPS = HTTP + 通信加密 + 证书 + 完整性保护

后边的三个可以通过SSL(Secure Socket Layer安全套接层)实现,所以 HTTPS = HTTP over SSL, HTTPS并不是一个新的协议,是一种组合实现的结果而已。

以前是在应用层HTTP协议与传输层TCP/IP直接建立通信连接,现在中间多了一个SSL。 就是先要与SSL通信,然后才与TCP/IP通信。

7.1 加密算法

以前常采用的加密算法叫做共享密钥算法,也叫做对称加密算法。这样有一个问题,就是怎么能够把共享的这个密钥安全的发给对方呢?如果中途被攻击,密钥被窃取就危险了。

所以后来就有了公开密钥算法,也叫做非对称加密算法。比如RSA算法。就是一对钥匙,发送方用公钥进行加密,然后发送内容,接收的一方用私钥进行解密。私有密钥不能让其他任何人知道,而公开密钥则可以随意发布,任何人都可以获得。

HTTPS采用的是上述两种加密方式的混合版本。因为从效率上来说,非对称加密确实慢一些,所以需要根据实际情况来决定使用哪一种加密方式。

非对称加密也有一个问题就是无法确保接收到的公钥就是你期望的。需要通过CA颁发公开密钥证书确认。这个证书可以粗解为 公钥 + 数字签名。客户端可使用数字证书认证机构的公开密钥,对那张证书上的数字签名进行验证,从而确认公钥的有效性。

7.2 HTTPS通信的步骤

  1. 客户端发送请求,开始SSL通信,报文中包括:客户端支持的SSL的指定版本、加密组件(Cipher Suite)列表(所使用的加密算法及密钥长度等)。

  2. 服务器返回一个响应报文,报文中包括SSL版本以及从客户端发过来的加密组件筛选出来的一些加密组件,这个过程就是加密组件协商。

  3. 服务器再发送Certificate报文,包含了含公钥的证书。

  4. 再发一个报文告知客户端SSL协议最初的协商阶段的握手结束了。

  5. 接着客户端来一波三连发,第一波发个请求报文,包含 Pre-master secret(随机密码串)。这个时候的报文已经用上面步骤获取到的公钥进行了加密。

  6. 第二波客户端再发报文,该报文会提示服务器,在此报文之后的通信会采用 Pre-master secret 密钥加密

  7. 客户端发送一个完成的报文,包含连接至今全部报文的整体校验值。这次握手成不成功就看服务器能不能正确的解析该报文了。

  8. 服务端响应一个同上第6的报文

  9. 服务端响应一个结束报文,SSL建立完成,剩下的就是开始HTTP连接。

在以上流程中,应用层发送数据时会附加一种叫做 MAC(Message Authentication Code)的报文摘要。MAC 能够查知报文是否遭到篡 改,从而保护报文的完整性。

HTTP,HTTPS相比,HTTPS更安全,但是也更加耗开销,更慢,所以分不同的应用场景。主要还是使用HTTP的多,但是如网银支付什么的还是HTTPS。

8. 用户认证