前言

对于前端工程师来说,每天都在和HTTP协议打交道,但是我真的懂HTTP协议吗?并没有,那么不如就现在开始了解吧。

1、开胃菜,从URL开始,发生了什么

1.1、网络栈构成

HTTP协议--通信、报文、缓存、跨域、安全 - 图1

1.2、数据包封包过程:

HTTP协议--通信、报文、缓存、跨域、安全 - 图2

1.3、TCP握手过程

HTTP协议--通信、报文、缓存、跨域、安全 - 图3

1.4、数据包传输过程:

HTTP协议--通信、报文、缓存、跨域、安全 - 图4

2、HTTP协议的主要特点

  1. 简单快速:每个资源是固定的,所以简单
  2. 灵活:每个头部指明了数据类型
  3. 无状态:每次连接都是一个新的链接,服务端不会记住连接的身份
  4. 无链接: 连接一次就会断开

    3、报文构成

    HTTP报文大致可分为报文首部和报文主题两块。两者由最初出现的空行(CR+LF)来划分。报文主体并不是必须的。
    HTTP协议--通信、报文、缓存、跨域、安全 - 图5

    3.1、请求报文

    HTTP协议--通信、报文、缓存、跨域、安全 - 图6
部分 功能
请求行 请求方法、URI、HTTP版本
请求头 key:value的键值对
空行 传输资源
请求体 传输资源

HTTP协议--通信、报文、缓存、跨域、安全 - 图7

3.2、响应报文

  1. ![](https://cdn.nlark.com/yuque/0/2018/png/147001/1532674823776-00da6072-1521-4794-bec1-5df9e9a00279.png)
部分 功能
状态行 响应结果的状态码、原因短语、HTTP版本
响应头 传输资源
空行 传输资源
响应体 传输资源

HTTP协议--通信、报文、缓存、跨域、安全 - 图8

常用内容编码:gzip,comparess,deflate,

4、HTTP方法

方法名 功能
GET 获取资源
POST 传输资源
PUT 更新资源
DELETE 删除资源
HEAD 获取头部信息

5、HTTP状态码及其作用

5.1、状态码大类说明

状态码 作用 详细说明
1xx Informational(指示信息) 表示请求已接收,继续处理
2xx Success(请求成功) 表示请求已被成功接收
3xx Redirection(重定向) 完成请求,必须进行更进一步的操作
4xx Client Error(客户端错误) 请求有语法错误或者请求无法实现
5xx Server Error(服务端错误) 服务器处理请求出错

5.2、常见的14种状态码举例(公有60+种)

HTTP CODE 2xx

状态码:200 ok
含义:客户端请求成功


状态码:204 No Content
含义:请求处理成功,但没有资源科返回。204不允许返回任何实体的主体


状态码:206 Partial Content
含义:客户发送了一个带有Range头的GET请求,服务器完成了它。使用video去播放视频,返回206,说明视频范围


HTTP CODE 3xx

状态码:301 Moved Permanently
含义:永久重定向。该状态吗表示请求的资源已被分配了新的URI,以后应按 Location 首部字段提示的 URI 重新保存。


状态码:302 Found
含义:和 301 Moved Permanently 状态码相似,但 302 状态码代表的资源不是被永久移动,只是临时性质的。


状态码:303 See Other
含义:303 状态码和 302 Found 状态码有着相同的功能,但 303 状态码明确表示客户端应当采用 GET 方法获取资源。


状态码:304 Not Modified
含义:

  1. 304 虽然被划分在 3XX 类别中,但是和重定向没有关系。
  2. 资源已找到,但未符合条件请求。

条件请求是啥:
采用 GET方法的请求报文中包含 If-MatchIf-ModifiedSinceIf-None-MatchIf-RangeIf-Unmodified-Since
中任一首部。


HTTP CODE 4xx


状态码:400 Bad Request
含义:请求报文中存在语法错误。当错误发生是,需要修改请求的内容后再次发送请求。
另外,浏览器会像200 OK一样对待该状态码。


状态码:401 Unauthorized
含义:返回含有 401 的响应必须包含一个适用于被请求资源的 WWW-Authenticate
首部用以质询(challenge)用户信息。当浏览器初次接收到 401 响应,会弹出认证用的对话窗口。


状态码:403 Forbidden
含义:该状态码表明对请求资源的访问被服务器拒绝了。服务器端没有必要给出拒绝的详细理由。
未获得文件系统的访问授权,访问权限出现某些问题(从未授权的发送源 IP 地址试图访问)等列举的情况都可能是发生 403 的原因。


状态码:404 Not Found
含义:该状态吗表明服务器上无法找到请求的资源。


HTTP CODE 5xx

状态码:500 Intertnal Server Error
含义:服务器本身发生错误。也有可能是 Web应用存在的 bug 或某些临时的故障


状态码:503 Intertnal Server Error
含义:该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。

6、缓存方案

6.1、强制缓存

HTTP协议--通信、报文、缓存、跨域、安全 - 图9

HTTP协议--通信、报文、缓存、跨域、安全 - 图10

Expires

Expires的值为服务端返回的到期时间,即下一次请求时,请求时间小于服务端返回的到期时间,直接使用缓存数据。
不过Expires 是HTTP 1.0的东西,现在默认浏览器均默认使用HTTP
1.1,所以它的作用基本忽略。
另一个问题是,到期时间是由服务端生成的,但是客户端时间可能跟服务端时间有误差,这就会导致缓存命中的误差。
所以HTTP 1.1 的版本,使用Cache-Control替代。

Cache-Control

Cache-Control 是最重要的规则。常见的取值有private、public、no-cache、max-age,no-store,默认为private。
private:客户端可以缓存
public:客户端和代理服务器都可缓存(前端的同学,可以认为public和private是一样的)
max-age=xxx:缓存的内容将在 xxx 秒后失效
no-cache:需要使用对比缓存来验证缓存数据(后面介绍)
no-store:所有内容都不会缓存,强制缓存,对比缓存都不会触发
HTTP协议--通信、报文、缓存、跨域、安全 - 图11
图中Cache-Control仅指定了max-age,所以默认为private,缓存时间为31536000秒(365天)

也就是说,在365天内再次请求这条数据,都会直接获取缓存数据库中的数据,直接使用。

6.2、协商缓存

HTTP协议--通信、报文、缓存、跨域、安全 - 图12
对比缓存,顾名思义,需要进行比较判断是否可以使用缓存。

浏览器第一次请求数据时,服务器会将缓存标识与数据一起返回给客户端,客户端将二者备份至缓存数据库中。
再次请求数据时,客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行判断,判断成功后,返回304状态码,通知客户端比较成功,可以使用缓存数据。

第一次访问

HTTP协议--通信、报文、缓存、跨域、安全 - 图13

第二次访问

HTTP协议--通信、报文、缓存、跨域、安全 - 图14
对于协商缓存来说,缓存标识的传递是我们着重需要理解的,它在请求header和响应header间进行传递,

一共分为两种标识传递,但是他们俩是相辅相成的,接下来,我们分开介绍。

Last-Modified / If-Modified-Since

Last-Modified

服务器在请求时,告诉浏览器资源最后修改的时间。
HTTP协议--通信、报文、缓存、跨域、安全 - 图15


If-Modified-Since:

再次请求服务器时,通过此字段通知服务器上次请求时,服务器返回的资源最后修改时间。

服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对。

若资源的最后修改时间大于If-Modified-Since,说明资源又被改动过,则响应整片资源内容,返回状态码200;

若资源的最后修改时间小于或等于If-Modified-Since,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache。
HTTP协议--通信、报文、缓存、跨域、安全 - 图16

Etag / If-None-Match(优先级高于Last-Modified / If-Modified-Since)

Etag:

服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。
HTTP协议--通信、报文、缓存、跨域、安全 - 图17


If-None-Match:

再次请求服务器时,通过此字段通知服务器客户段缓存数据的唯一标识。

服务器收到请求后发现有头If-None-Match 则与被请求资源的唯一标识进行比对,

不同,说明资源又被改动过,则响应整片资源内容,返回状态码200;

相同,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache。

  1. ![](https://cdn.nlark.com/yuque/0/2018/png/147001/1532674999323-75f3a89a-45ce-4d36-a7e9-adc618eeae5e.png)

总结:

对于强制缓存,服务器通知浏览器一个缓存时间,在缓存时间内,下次请求,直接用缓存,不在时间内,执行比较缓存策略。
对于协商缓存,将缓存信息中的Etag和Last-Modified通过请求发送给服务器,由服务器校验,返回304状态码时,浏览器直接使用缓存。
ps:通过Html页面设置HTTP请求头信息

  1. <meta http-equiv="Expires" content="0">
  2. <meta http-equiv="Pragma" content="no-cache">
  3. <meta http-equiv="Cache-control" content="no-cache">
  4. <meta http-equiv="Cache" content="no-cache">

7、通过HTML设置HTTP头部信息

http-equiv顾名思义,相当于http的文件头作用,它可以向浏览器传回一些有用的信息,以帮助正确和精确地显示网页内容,与之对应的属性值为content,content中的内容其实就是各个参数的变量值。

meta标签的http-equiv属性语法格式是:

其中http-equiv属性主要有以下几种参数:

A、Expires(期限)

说明:可以用于设定网页的到期时间。一旦网页过期,必须到服务器上重新传输。
用法:
注意:必须使用GMT的时间格式。

B、Pragma(cache模式)

说明:禁止浏览器从本地计算机的缓存中访问页面内容。
用法:
注意:这样设定,访问者将无法脱机浏览。

C、Refresh(刷新)

说明:自动刷新并指向新页面。
用法:(注意后面的引号,分别在秒数的前面和网址的后面)
注意:其中的2是指停留2秒钟后自动刷新到URL网址。

D、Set-Cookie(cookie设定)

说明:如果网页过期,那么存盘的cookie将被删除。
用法:
注意:必须使用GMT的时间格式。

E、Window-target(显示窗口的设定)

说明:强制页面在当前窗口以独立页面显示。
用法:
注意:用来防止别人在框架里调用自己的页面。

F、content-Type(显示字符集的设定)

说明:设定页面使用的字符集。
用法:

G、content-Language(显示语言的设定)

用法:

H、Cache-Control指定请求和响应遵循的缓存机制。

Cache-Control指定请求和响应遵循的缓存机制。
在请求消息或响应消息中设置Cache-Control并不会修改另一个消息处理过程中的缓存处理过程。
请求时的缓存指令包括no-cache、no-store、max-age、max-stale、min-fresh、only-if-cached,
响应消息中的指令包括public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age。
各个消息中的指令含义如下:

Public 指示响应可被任何缓存区缓存
Private 指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效
no-cache 指示请求或响应消息不能缓存
no-store 用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。
max-age 指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应
min-fresh 指示客户机可以接收响应时间小于当前时间加上指定时间的响应
max-stale 指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。

8、跨域——跨域资源共享(CORS)

当一个资源从与该资源本身所在的服务器不同的域或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
跨域并非不一定是浏览器限制了发起跨站请求,而也可能是跨站请求可以正常发起,但是返回结果被浏览器拦截了。
最好的例子是 CSRF 跨站攻击原理,请求是发送到了后端服务器无论是否跨域!
注意:有些浏览器不允许从 HTTPS 的域跨域访问 HTTP,比如 Chrome 和 Firefox,这些浏览器在请求还未发出的时候就会拦截请求,这是一个特例。
HTTP协议--通信、报文、缓存、跨域、安全 - 图18
跨域资源共享( CORS )机制允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。浏览器支持在 API 容器中(例如 XMLHttpRequest 或 Fetch )使用 CORS,以降低跨域 HTTP 请求所带来的风险。


简单请求

满足下述所有条件,称这个请求为简单请求,这样的请求不会触发CORS。
HTTP协议--通信、报文、缓存、跨域、安全 - 图19
A、使用录入GET、HEAD、POST方法
B、Content-Type 的值仅限于下列三者之一:

  1. text/plain
  2. multipart/form-data
  3. application/x-www-form-urlencoded

    预检请求

    与前述简单请求不同,“需预检的请求”要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。
    A、使用了任一HTTP方法:PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH
    B、 Content-Type 的值不属于下列之一:

  4. text/plain

  5. multipart/form-data
  6. application/x-www-form-urlencoded

HTTP协议--通信、报文、缓存、跨域、安全 - 图20

预检请求

  1. 1.OPTIONS /resources/post-here/ HTTP/1.1
  2. 2.Host: bar.other
  3. 3.User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
  4. 4.Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  5. 5.Accept-Language: en-us,en;q=0.5
  6. 6.Accept-Encoding: gzip,deflate
  7. 7.Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
  8. 8.Connection: keep-alive
  9. 9.Origin: http://foo.example
  10. 10.Access-Control-Request-Method: POST
  11. 11.Access-Control-Request-Headers: X-PINGOTHER, Content-Type
  12. 12.
  13. 13.
  14. 14.HTTP/1.1 200 OK
  15. 15.Date: Mon, 01 Dec 2008 01:15:39 GMT
  16. 16.Server: Apache/2.0.61 (Unix)
  17. 17.Access-Control-Allow-Origin: http://foo.example
  18. 18.Access-Control-Allow-Methods: POST, GET, OPTIONS
  19. 19.Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
  20. 20.Access-Control-Max-Age: 86400
  21. 21.Vary: Accept-Encoding, Origin
  22. 22.Content-Encoding: gzip
  23. 23.Content-Length: 0
  24. 24.Keep-Alive: timeout=2, max=100
  25. 25.Connection: Keep-Alive
  26. 26.Content-Type: text/plain

预检请求完成之后,发送实际请求:

  1. POST /resources/post-here/ HTTP/1.1
  2. Host: bar.other
  3. User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
  4. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  5. Accept-Language: en-us,en;q=0.5
  6. Accept-Encoding: gzip,deflate
  7. Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
  8. Connection: keep-alive
  9. X-PINGOTHER: pingpong
  10. Content-Type: text/xml; charset=UTF-8
  11. Referer: http://foo.example/examples/preflightInvocation.html
  12. Content-Length: 55
  13. Origin: http://foo.example
  14. Pragma: no-cache
  15. Cache-Control: no-cache
  16. <?xml version="1.0"?><person><name>Arun</name></person>
  17. HTTP/1.1 200 OK
  18. Date: Mon, 01 Dec 2008 01:15:40 GMT
  19. Server: Apache/2.0.61 (Unix)
  20. Access-Control-Allow-Origin: http://foo.example
  21. Vary: Accept-Encoding, Origin
  22. Content-Encoding: gzip
  23. Content-Length: 235
  24. Keep-Alive: timeout=2, max=99
  25. Connection: Keep-Alive
  26. Content-Type: text/plain
  27. [Some GZIP'd payload]

附带身份凭证的请求

将 XMLHttpRequest 的 withCredentials 标志设置为 true,从而向服务器发送 Cookies。因为这是一个简单 GET请求,所以浏览器不会对其发起“预检请求”。

但是,如果服务器端的响应中未携带 Access-Control-Allow-Credentials: true ,浏览器将不会把响应内容返回给请求的发送者。

9、HTTP 响应首部字段(跳过)

Access-Control-Allow-Origin

origin 参数的值指定了允许访问该资源的外域 URI.

  1. Access-Control-Allow-Origin: <origin> | *

Access-Control-Expose-Headers

在跨域访问时,XMLHttpRequest对象的getResponseHeader()方法只能拿到一些最基本的响应头,Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要访问其他头,则需要服务器设置本响应头。

  1. Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header

Access-Control-Max-Age

delta-seconds 参数表示preflight请求的结果在多少秒内有效。

  1. Access-Control-Max-Age: <delta-seconds>

Access-Control-Allow-Credentials

Access-Control-Allow-Credentials 头指定了当浏览器的credentials设置为true时是否允许浏览器读取response的内容。

Access-Control-Allow-Methods

Access-Control-Allow-Headers

Access-Control-Allow-Headers 首部字段用于预检请求的响应。其指明了实际请求中允许携带的首部字段。

  1. Access-Control-Allow-Headers: <field-name>[, <field-name>]*

HTTP 请求首部字段(跳过)

Origin

origin 参数的值为源站 URI。

  1. Origin: <origin>

Access-Control-Request-Method

Access-Control-Request-Method 首部字段用于预检请求。其作用是,将实际请求所使用的 HTTP 方法告诉服务器。

  1. Access-Control-Request-Method: <method>

Access-Control-Request-Headers

Access-Control-Request-Headers 首部字段用于预检请求。其作用是,将实际请求所携带的首部字段告诉服务器。

  1. Access-Control-Request-Headers: <field-name>[, <field-name>]*

10、CSRF攻击

CSRF跨站请求伪造

10.1、原理

HTTP协议--通信、报文、缓存、跨域、安全 - 图21
透过例子能够看出,攻击者并不能通过CSRF攻击来直接获取用户的账户控制权,也不能直接窃取用户的任何信息。他们能做到的,是欺骗用户浏览器,让其以用户的名义执行操作。

10.2、防御措施

  1. 检查Referer字段
  2. 添加校验token

参考文献:7
图解HTTP
图解HTTP.pdf