前言
对于前端工程师来说,每天都在和HTTP协议打交道,但是我真的懂HTTP协议吗?并没有,那么不如就现在开始了解吧。
0、开胃菜,从URL开始,发生了什么
0.0、网络栈构成
0.1、数据包封包过程:
0.2、数据包传输过程:
1、HTTP协议的主要特点
- 简单快速:每个资源是固定的,所以简单
- 灵活:每个头部指明了数据类型
- 无状态:每次连接都是一个新的链接,服务端不会记住连接的身份
- 无链接: 连接一次就会断开
2、报文构成
HTTP报文大致可分为报文首部和报文主题两块。两者由最初出现的空行(CR+LF)来划分。报文主体并不是必须的。
1、请求报文
部分 | 功能 |
---|---|
请求行 | 请求方法、URI、HTTP版本 |
请求头 | key:value的键值对 |
空行 | 传输资源 |
请求体 | 传输资源 |
2、响应报文
部分 | 功能 |
---|---|
状态行 | 响应结果的状态码、原因短语、HTTP版本 |
响应头 | 传输资源 |
空行 | 传输资源 |
响应体 | 传输资源 |
常用内容编码:gzip,comparess,deflate,
3、HTTP方法
方法名 | 功能 |
---|---|
GET | 获取资源 |
POST | 传输资源 |
PUT | 更新资源 |
DELETE | 删除资源 |
HEAD | 获取头部信息 |
4、HTTP状态码及其作用
1、状态码大类说明
状态码 | 作用 | 详细说明 |
---|---|---|
1xx | Informational(指示信息) | 表示请求已接收,继续处理 |
2xx | Success(请求成功) | 表示请求已被成功接收 |
3xx | Redirection(重定向) | 完成请求,必须进行更进一步的操作 |
4xx | Client Error(客户端错误) | 请求有语法错误或者请求无法实现 |
5xx | Server Error(服务端错误) | 服务器处理请求出错 |
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-Match
,If-ModifiedSince
,If-None-Match
,If-Range
,If-Unmodified-Since
中任一首部。
HTTP CODE 4xx
国内用的人极少,都是4字头的问题,也就是车本身的问题,延伸为都是客户端的问题。
状态码: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
含义:该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。
3、缓存方案
1、强制缓存
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: 所有内容都不会缓存,强制缓存,对比缓存都不会触发
图中Cache-Control仅指定了max-age,所以默认为private,缓存时间为31536000秒(365天)
也就是说,在365天内再次请求这条数据,都会直接获取缓存数据库中的数据,直接使用。
2、协商缓存
对比缓存,顾名思义,需要进行比较判断是否可以使用缓存。
浏览器第一次请求数据时,服务器会将缓存标识与数据一起返回给客户端,客户端将二者备份至缓存数据库中。
再次请求数据时,客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行判断,判断成功后,返回304状态码,通知客户端比较成功,可以使用缓存数据。
第一次访问
第二次访问
对于协商缓存来说,缓存标识的传递是我们着重需要理解的,它在请求header和响应header间进行传递,
一共分为两种标识传递,但是他们俩是相辅相成的,接下来,我们分开介绍。
Last-Modified / If-Modified-Since
Last-Modified
服务器在请求时,告诉浏览器资源最后修改的时间。
If-Modified-Since:
再次请求服务器时,通过此字段通知服务器上次请求时,服务器返回的资源最后修改时间。
服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对。
若资源的最后修改时间大于If-Modified-Since,说明资源又被改动过,则响应整片资源内容,返回状态码200;
若资源的最后修改时间小于或等于If-Modified-Since,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache。
Etag / If-None-Match(优先级高于Last-Modified / If-Modified-Since)
Etag:
服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。
If-None-Match:
再次请求服务器时,通过此字段通知服务器客户段缓存数据的唯一标识。
服务器收到请求后发现有头If-None-Match 则与被请求资源的唯一标识进行比对,
不同,说明资源又被改动过,则响应整片资源内容,返回状态码200;
相同,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache。
总结:
对于强制缓存,服务器通知浏览器一个缓存时间,在缓存时间内,下次请求,直接用缓存,不在时间内,执行比较缓存策略。
对于协商缓存,将缓存信息中的Etag和Last-Modified通过请求发送给服务器,由服务器校验,返回304状态码时,浏览器直接使用缓存。
4、跨域—-跨域资源共享
当一个资源从与该资源本身所在的服务器不同的域或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
跨域并非不一定是浏览器限制了发起跨站请求,而也可能是跨站请求可以正常发起,但是返回结果被浏览器拦截了。
最好的例子是 CSRF 跨站攻击原理,请求是发送到了后端服务器无论是否跨域!
注意:有些浏览器不允许从 HTTPS 的域跨域访问 HTTP,比如 Chrome 和 Firefox,这些浏览器在请求还未发出的时候就会拦截请求,这是一个特例。
跨域资源共享( CORS )机制允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。浏览器支持在 API 容器中(例如 XMLHttpRequest 或 Fetch )使用 CORS,以降低跨域 HTTP 请求所带来的风险。
简单请求
满足下述所有条件,称这个请求为简单请求,这样的请求不会触发CORS。
A、使用录入GET、HEAD、POST方法
B、Content-Type 的值仅限于下列三者之一:
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
预检请求
与前述简单请求不同,“需预检的请求”要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。
A、使用了任一HTTP方法:PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH
B、 Content-Type 的值不属于下列之一:
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
预检请求
1.OPTIONS /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.Origin: http://foo.example
10.Access-Control-Request-Method: POST
11.Access-Control-Request-Headers: X-PINGOTHER, Content-Type
12.
13.
14.HTTP/1.1 200 OK
15.Date: Mon, 01 Dec 2008 01:15:39 GMT
16.Server: Apache/2.0.61 (Unix)
17.Access-Control-Allow-Origin: http://foo.example
18.Access-Control-Allow-Methods: POST, GET, OPTIONS
19.Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
20.Access-Control-Max-Age: 86400
21.Vary: Accept-Encoding, Origin
22.Content-Encoding: gzip
23.Content-Length: 0
24.Keep-Alive: timeout=2, max=100
25.Connection: Keep-Alive
26.Content-Type: text/plain
预检请求完成之后,发送实际请求:
POST /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
X-PINGOTHER: pingpong
Content-Type: text/xml; charset=UTF-8
Referer: http://foo.example/examples/preflightInvocation.html
Content-Length: 55
Origin: http://foo.example
Pragma: no-cache
Cache-Control: no-cache
<?xml version="1.0"?><person><name>Arun</name></person>
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:40 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain
[Some GZIP'd payload]
附带身份凭证的请求
将 XMLHttpRequest 的 withCredentials 标志设置为 true,从而向服务器发送 Cookies。因为这是一个简单 GET请求,所以浏览器不会对其发起“预检请求”。
但是,如果服务器端的响应中未携带 Access-Control-Allow-Credentials: true ,浏览器将不会把响应内容返回给请求的发送者。
HTTP 响应首部字段(跳过)
Access-Control-Allow-Origin
origin 参数的值指定了允许访问该资源的外域 URI.
Access-Control-Allow-Origin: <origin> | *
Access-Control-Expose-Headers
在跨域访问时,XMLHttpRequest对象的getResponseHeader()方法只能拿到一些最基本的响应头,Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要访问其他头,则需要服务器设置本响应头。
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
Access-Control-Max-Age
delta-seconds
参数表示preflight请求的结果在多少秒内有效。
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 首部字段用于预检请求的响应。其指明了实际请求中允许携带的首部字段。
Access-Control-Allow-Headers: <field-name>[, <field-name>]*
HTTP 请求首部字段(跳过)
Origin
origin 参数的值为源站 URI。
Origin: <origin>
Access-Control-Request-Method
Access-Control-Request-Method 首部字段用于预检请求。其作用是,将实际请求所使用的 HTTP 方法告诉服务器。
Access-Control-Request-Method: <method>
Access-Control-Request-Headers
Access-Control-Request-Headers 首部字段用于预检请求。其作用是,将实际请求所携带的首部字段告诉服务器。
Access-Control-Request-Headers: <field-name>[, <field-name>]*
CSRF攻击
CSRF跨站请求伪造
原理
透过例子能够看出,攻击者并不能通过CSRF攻击来直接获取用户的账户控制权,也不能直接窃取用户的任何信息。他们能做到的,是欺骗用户浏览器,让其以用户的名义执行操作。
防御措施
1、检查Referer字段
2、添加校验token
通过HTML页面设置缓存方案
对于一个html页面,缓存分3部分,一个是页面内容,一个是css样式,一个是JS文件
1、页面内容
<meta http-equiv="Expires" content="0">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-control" content="no-cache">
<meta http-equiv="Cache" content="no-cache">
2、CSS和JS文件
<link rel="stylesheet" href="../css/register.css"/>
<script src="../scripts/register.js"></script>
改成
<link rel="stylesheet" href="../css/register.css?v=20161020"/>
<script src="../scripts/register.js?v=20161020"></script>
就是只要在每次修改后改一下版本号即可
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 : 指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。只接受 Age 值小于 max-age 值,并且没有过期的对象
min-fresh : 指示客户机可以接收响应时间小于当前时间加上指定时间的响应
max-stale : 指示客户机可以接收超出超时期间的响应消息。可以接受过去的对象,但是过期时间必须小于 max-stale 值。
如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。
参考文献:
图解HTTP
前端团队语雀平台地址