http缓存和CORS

623 阅读5分钟

报文结构

请求头(request headers)、响应头(response headers)、请求体(FormData, request body)、响应体(response)

缓存

原本地址

缓存有两种,强缓存和协商缓存。如果强缓存存在,那么执行强缓存,如果不存在则执行协商缓存。

强制缓存

本地缓存,本地存在一个存在一个缓存数据库, 如果缓存数据库中存在所请求的数据的时候,直接从本地缓存数据库里获取。强制缓存有两个字段表明 cache-control和expires

  • Expires 缓存到期的时间,精确到秒。但由于服务端时间和客户端时间可能有误差,这也将导致缓存命中的误差。Expires是http1.0的产物,故现在主要使用的还是cache-control。并且Cache-control的优先级比Expires的高
  • Cache-control 有多个值
    • max-age: t秒 t表示一个时间,上一次访问后多久失效。上一次的时间应该是date对应的字段
    • no-store 禁止缓存,每次都从服务器重新获取200
    • no-chche 使用协商缓存来获取数据
    • public 客户端和代理服务区都可以缓存
    • private 客户端缓存

协商缓存

协商缓存有两组数据Last-Modified/if-Modified-Since和Etag/If-None-Match

  • Last-Modified/if-Modified-Since:Last-Modified表示上次被修改的时间,在第一次请求的时候会在响应头里面返回。如果再次请求会在请求头的携带上if-Modified-Since(如果是协商缓存的话),if-Modified-Since的值就是第一次请求的Last-Modified的值。服务器拿到if-Modified-Since的值跟实际被修改的时间做对比,如果小于实际被修改的时间,那么服务器重新请求资源,返回200。否则返回403,告诉客户端使用本地缓存(from memory cache)
  • Etag/If-None-Match:Etag是服务器根据当前文件的内容,给文件生成的唯一标识,只要里面的内容有改动,这个值就会变,相当于文件的hash值。工作原理跟Last-Modified/if-Modified-Since基本一样。不同的是一个是时间一个是 唯一标识
两种协商缓存对比

在精准度上,ETag优于Last-Modified。优于 ETag 是按照内容给资源上标识,因此能准确感知资源的变化。而 Last-Modified 就不一样了,它在一些特殊的情况并不能准确感知资源变化,主要有两种情况:

  • 编辑了资源文件,但是文件内容并没有更改,这样也会造成缓存失效。
  • Last-Modified 能够感知的单位时间是秒,如果文件在 1 秒内改变了多次,那么这时候的 Last-Modified 并没有体现出修改了。

在性能上,Last-Modified优于ETag,也很简单理解,Last-Modified仅仅只是记录一个时间点,而 Etag需要根据文件的具体内容生成哈希值。另外,如果两种方式都支持的话,服务器会优先考虑ETag。

状态码

COSR和两种请求方式

原本地址

CORS(Cross-origin resource sharing),跨域资源共享。浏览器遵循同源政策,协议(http,还是https),主机IP,端口相同则是同源。跨域请求会被浏览器拦截,注意是浏览器拦截,不是服务器拦截,数据会发送到浏览器。

两种请求方式:简单请求和非简单请求

简单请求

符合以下条件的即为简单请求

  • 请求方式为 GET POST HEAD
  • 请求头为以下字段(以下只是列举了一部分,其实还有很多,查看了很多文档,但是文档的内容好像都不大一样)
    • Accept 接受的返回数据类型
    • Accept-Language
    • Content-Language
    • Content-Type 发送的数据类型(只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain)
    • Referer 直译为推荐人。表示从哪个域名跳转过来
    • User-Agent

实际过程中主要看请求方式是否为GET POST HEAD,在就是Content-Type的值,上传必定为非简单请求,因为他的Content-Type 不是该三个值里面的一个。在者就是是否往请求头里面添加自定字段,如果添加则为分简单请求。

Access-Control-Allow-Credentials 表示是否允许发送Cookie。跨域默认该值为false,如果需要发送Cookie,那么在响应头里面设置该值为true,并且在前端也要设置withCredentials为true

access-control-expose-header 响应头返回的字段默认就那几个,如果想展示更多,会在改值里面显示

非简单请求

在进行预检请求之前会发送预检请求,预检请求的请求方式为OPTIONS,如果预检请求没有通过(跨域),那么不会进行非正常请求。预检请求是否通过主要是请求头的三个字段

  • Origin
  • Access-Control-Request-Method 请求方式
  • Access-Control-Request-Headers 在请求头添加那个自定义字段

预检请求响应字段

  • Access-Control-Allow-Origin 允许请求的源列表 * 表示任何都可以请求
  • Access-Control-Allow-Methods 允许请求的方法列表
  • Access-Control-Allow-Headers 允许请求的自定义请求头字段
  • access-control-allow-credentials 是否发送Cookie
  • Access-Control-Max-Age 预检请求有效时间,多久不用发送预检请求

预检请求请求头字段和响应头字段比较,浏览就知道这个预检请求是否通过,通过之后发送真正的非简单请求。真正的非简单请求和简单请求一样。

简单请求和非简单请求的是否跨域都是有Origin和Access-Control-Allow-Origin决定

正向代理,反向代理

代理服务器与正真的服务器如果是一对一的,那么是正向代理,如果是一对多,那么是反向代理,nginx就是反向代理

跨域的解决方案

  • jsonp
  • nginx(原理就是请求转发,nginx只是工具)
  • postmessage(客户端之间)
server {
  listen  80;
  server_name  client.com;
  location /api {
    proxy_pass server.com;
  }
}