HTTP 笔记(下)

date
Nov 6, 2018
slug
http-note-2
status
Published
tags
HTTP
summary
Http 中的跨域、缓存
type
Post
跨域、缓存这些都是开发中常常遇到的,做些笔记供日后查阅。

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)
对于能满足以下俩大条件的即为简单请求:
  1. 请求方法是以下三种之一:
  • GET
  • HEAD
  • POST
  1. 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返回给浏览器后,浏览器阻挡了该请求:
notion image
解决办法就是在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 的设置来决定。

强缓存

强缓存有浏览器设置在内存中,直接从内存中读取,而不去服务器拉取数据。
强缓存的具体设置有俩种:
  1. http 1.0 中设置 expires。如:` 'expires': 'Mon, 10 Jun 2015 21:31:12 GMT'` 发送请求的时间在此之前,缓存均有效。
  1. 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 是协商缓存的俩种方式,都是在服务器端的响应头中设置。不同之处在于:
  1. 一些文件可能会定时的更新,但是内容未被更改。这个时候如果使用 Last-Modified 的话就会被认为文件被修改了,而 etag 则不会,因为 etag 是服务器上每个资源的唯一标识。可以根据文件内容生成 hash 来设置 etag。
  1. 对于某些修改频繁的文件来说,频率在秒以内。Last-Modified 只能精确到秒,所以这种情况无法判断。
这俩者的值可以随便设置,没有具体的规定。

Last-Modified/If-Modified-Since

具体过程:
  1. 在服务端响应头上设置 'Last-Modified': ''
  1. 请求再次发送到服务器后,请求头中会出现 'If-Modified-Since': '' (这个值与上述设置的值相同)
  1. 再次发送请求到服务器后会判断俩者的值,如果没有变化则返回 304 Not Modified,但是不会返回资源内容;如果有变化,就正常返回资源内容。当服务器返回 304 Not Modified 的响应时,浏览器就会从内存中读取缓存。这个动作就是协商后的结果。
  1. 如果缓存没有命中,就直接从服务器加载数据。此时会更新响应头中的 Last-Modified 的信息,供下次对比使用。

Etag/If-None-Match

etag 具体过程与上相同。

总结

虽说没有具体规定要设置的值,但是 Last-Modified 一般设置为时间,即文件最后一次的更新时间。而 Etag 则设置为根据内容生成的 hash 值。

参考资料


© i7eo 2017 - 2024