HTTP 笔记(下)
date
Nov 6, 2018
slug
http-note-2
status
Published
tags
HTTP
summary
Http 中的跨域、缓存
type
Post
跨域、缓存这些都是开发中常常遇到的,做些笔记供日后查阅。
CORS(Cross-Origin Resource Sharing)跨源资源分享同源策略CORS & JSONPCROSJSONP缓存强缓存协商缓存Last-Modified/If-Modified-SinceEtag/If-None-Match总结参考资料
CORS(Cross-Origin Resource Sharing)跨源资源分享
同源策略
同源策略(same-origin policy)是浏览器保障安全的一种方法。
主要指的是在同协议,同域名,同端口下才能访问资源。为什么要这样限制?假设某用户登陆了自己的网上网上银行,接着去访问了其他网站,如果没有同源策略的限制,那么其他网站就可以访问银行网站的cookie,而cookie一般存放着与用户相关的某些信息,这样用户的信息就会被泄漏或者被冒名顶替去访问网上银行。
CORS & JSONP
正是源于上述的策略,导致在开发中出现跨域的问题。那么如何跨过这个限制呢?常见的有:
- cors
- jsonp
- websocket
- postMessage
- iframe
具体可以参考这篇文章:前端常见跨域解决方案(全)这里主要说一说常见的 cors 与 jsonp
CROS
CORS 指的是跨源资源分享,具体的实现分为俩类:
- 简单请求(simple request)
- 预请求(preflight request)
对于能满足以下俩大条件的即为简单请求:
- 请求方法是以下三种之一:
- GET
- HEAD
- POST
- http 的头信息不能超出以下几种字段:
- Accept
- Accept - Language
- Content - Language
- Content - type
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
而不满足如上条件的即为预请求。
假设现在开启了端口8888、8887 俩个 node 服务,当8888上的页面请求8887的时候,请求其实是已经发送到了8887。请求头中多出了
origin
字段,但是此时服务器中并没有设置相应的 Access-Control-Allow-Origin
所以当请求从8887返回给浏览器后,浏览器阻挡了该请求:解决办法就是在8887上的响应头中添加
'Access-Control-Allow-Origin': '*'
这里的 * 表示通配符,当然你还可以根据需要设置成单一的地址,比如: 'Access-Control-Allow-Origin': '<http://127.0.0.1:8888>'
当你在请求头中设置了 PUT 或者 自定义信息(token 等)这个时候需要在响应头上添加:
'Access-Control-Allow-Methods': 'PUT, Delete', 'Access-Control-Allow-Headers': 'Token'
,这是为了让服务器支持对应的信息,这里需要注意的是在8888发送请求前会多发送一条方法为 OPTIONS
的请求来进行预请求。还可以设置时间使接下来的请求中不带有这条预请求,即: 'Access-Control-Max-Age': '1000'
(单位为秒)在 1000s 内不会再发送预请求。JSONP
浏览器允许跨域资源的嵌入。具体如下:
- <script src="..."></script> 标签嵌入跨域脚本。语法错误信息只能在同源脚本中捕捉到。
- <link rel="stylesheet" href="..."> 标签嵌入CSS。由于CSS的松散的语法规则,CSS的跨域需要一个设置正确的Content-Type 消息头
- <img> 嵌入图片。支持的图片格式包括PNG,JPEG,GIF,BMP,SVG...
- <video> 和 <audio> 嵌入多媒体资源。
- <frame> 和 <iframe>
- @font-face 引入的字体。一些浏览器允许跨域字体( cross-origin fonts),一些需要同源字体(same-origin fonts)。
- <object>, <embed> 和 <applet> 的插件。
jsonp 正式运用了第一条规则,将数据利用如下形式包装在请求的js文件中:cors({}) 然后在发出请求的地址后面加上 callback=cors 即可通过 cors 获得数据。
缓存
浏览器的缓存有俩种,即强缓存与协商缓存。具体选用哪一种由 header 的设置来决定。
强缓存
强缓存有浏览器设置在内存中,直接从内存中读取,而不去服务器拉取数据。
强缓存的具体设置有俩种:
- http 1.0 中设置 expires。如:` 'expires': 'Mon, 10 Jun 2015 21:31:12 GMT'` 发送请求的时间在此之前,缓存均有效。
- http 1.1 中设置 cache-control 。如:` 'cache-control': 'max-age=20'`(单位为秒)
这里需要注意的是,一般使用 cache-control (客户端缓存)时,设置的时间都较长。此时如果修改js文件的话,是不会生效的。解决方法就是在项目构建文件中跟js文件的内容生成hash值,这样强缓存就会及时更新。还可以设置其他属性,如下:
- 可缓存性:
- public 除了浏览器与服务器,代理服务器也可以缓存
- private 只有发起请求的浏览器才可以缓存
- no-cache 需要与服务器进行协商,是否能使用本地缓存
- no-store 本地与缓存服务器均不能使用缓存
- 到期
- max-age
- s-maxage 只有在代理服务器中生效
- max-stale 指发起请求方缓存过期后还可以使用过期缓存的时间
- 重新验证
- must-revalidate 在max-age过期后,重新发送请求验证是否真正过期
- proxy-revalidate 在max-age过期后,重新发送请求至缓存服务器验证是否真正过期
- 其他
- no-transform 告诉proxy不要压缩缓存
例子:
'cache-control': 'public, max-age=200, no-cache'
协商缓存
Last-Modified/Etag 是协商缓存的俩种方式,都是在服务器端的响应头中设置。不同之处在于:
- 一些文件可能会定时的更新,但是内容未被更改。这个时候如果使用 Last-Modified 的话就会被认为文件被修改了,而 etag 则不会,因为 etag 是服务器上每个资源的唯一标识。可以根据文件内容生成 hash 来设置 etag。
- 对于某些修改频繁的文件来说,频率在秒以内。Last-Modified 只能精确到秒,所以这种情况无法判断。
这俩者的值可以随便设置,没有具体的规定。
Last-Modified/If-Modified-Since
具体过程:
- 在服务端响应头上设置 'Last-Modified': ''
- 请求再次发送到服务器后,请求头中会出现 'If-Modified-Since': '' (这个值与上述设置的值相同)
- 再次发送请求到服务器后会判断俩者的值,如果没有变化则返回 304 Not Modified,但是不会返回资源内容;如果有变化,就正常返回资源内容。当服务器返回 304 Not Modified 的响应时,浏览器就会从内存中读取缓存。这个动作就是协商后的结果。
- 如果缓存没有命中,就直接从服务器加载数据。此时会更新响应头中的 Last-Modified 的信息,供下次对比使用。
Etag/If-None-Match
etag 具体过程与上相同。
总结
虽说没有具体规定要设置的值,但是
Last-Modified
一般设置为时间,即文件最后一次的更新时间。而 Etag
则设置为根据内容生成的 hash 值。