缓存图像的CORS策略

时间:2012-09-29 00:12:35

标签: javascript html5 canvas amazon-s3 cross-domain

在chrome 22&野生动物园6。

使用支持CORS的S3存储桶从s3加载图像以在画布中使用(以提取为主要目的),使用以下代码:

<!-- In the html -->
<img src="http://s3....../bob.jpg" /> 

// In the javascript, executed after the dom is rendered
this.img = new Image();
this.img.crossOrigin = 'anonymous';
this.img.src = "http://s3....../bob.jpg";

我观察到以下情况:

  1. 禁用缓存
  2. 一切正常,图片加载
  3. 然后在启用缓存的情况下尝试:

    1. 启用缓存
    2. DOM图像加载,画布图像创建dom安全例外
    3. 如果我修改代码的javascript部分以附加查询字符串,如下所示:

      this.img = new Image();
      this.img.crossOrigin = 'anonymous';
      this.img.src = "http://s3....../bob.jpg?_";
      

      一切正常,即使完全启用了缓存也是如此。我通过使用http代理继续进行缓存是一个问题,并观察到在失败的情况下,实际上没有从服务器请求图像。

      我不得不得出的结论是图像缓存正在保存原始请求标头,然后将其用于后续启用CORS的请求 - 并且由于违反相同的源策略而生成安全性异常

      这是预期的行为吗?

      编辑:在Firefox中运行。

      Edit2:关于s3存储桶的Cors政策

      <?xml version="1.0" encoding="UTF-8"?>
      <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
          <CORSRule>
              <AllowedOrigin>*</AllowedOrigin>
              <AllowedMethod>GET</AllowedMethod>
          </CORSRule>
      </CORSConfiguration>
      

      我正在使用大开放,因为我现在只是在本地方框中进行测试。这还没有投入生产。

      Edit3:更新了cors策略以指定原点

      <?xml version="1.0" encoding="UTF-8"?>
      <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
          <CORSRule>
              <AllowedOrigin>http://localhost:5000</AllowedOrigin>
              <AllowedMethod>GET</AllowedMethod>
          </CORSRule>
      </CORSConfiguration>
      

      已验证的传出标题:

      Origin  http://localhost:5000
      Accept  */*
      Referer http://localhost:5000/builder
      Accept-Encoding gzip,deflate,sdch
      Accept-Language en-US,en;q=0.8
      Accept-Charset  ISO-8859-1,utf-8;q=0.7,*;q=0.3
      

      传入标题:

      Access-Control-Allow-Origin http://localhost:5000
      Access-Control-Allow-Methods    GET
      Access-Control-Allow-Credentials    true
      

      如果我在加载到画布时没有破坏缓存,则仍然无法使用chrome。

      编辑4:

      在失败的情况下注意到这一点。

      传出标题:

      GET /373c88b12c7ba7c513081c333d914e8cbd2cf318b713d5fb993ec1e7 HTTP/1.1
      Host    amir.s3.amazonaws.com
      User-Agent  Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.91 Safari/537.4
      Accept  */*
      Referer http://localhost:5000/builder
      Accept-Encoding gzip,deflate,sdch
      Accept-Language en-US,en;q=0.8
      Accept-Charset  ISO-8859-1,utf-8;q=0.7,*;q=0.3
      If-None-Match   "99c958e2196c60aa8db385b4be562a92"
      If-Modified-Since   Sat, 29 Sep 2012 13:53:34 GMT
      

      传入标题:

      HTTP/1.1 304 Not Modified
      x-amz-id-2  3bzllzox/vZPGSn45Y21/vh1Gm/GiCEoIWdDxbhlfXAD7kWIhMKqiSEVG/Q5HqQi
      x-amz-request-id    48DBC4559B5B840D
      Date    Sat, 29 Sep 2012 13:55:21 GMT
      Last-Modified   Sat, 29 Sep 2012 13:53:34 GMT
      ETag    "99c958e2196c60aa8db385b4be562a92"
      Server  AmazonS3
      

      认为这是由dom触发的第一个请求。我不知道这不是javascript请求。

3 个答案:

答案 0 :(得分:10)

问题是图像是从以前的请求缓存而没有所需的CORS头。因此,当你再次要求它时,对于画布,使用&#39; crossorigin&#39;指定,浏览器使用缓存版本,没有看到必要的标题,并引发CORS错误。 当你添加&#39;?_&#39;对于URL,浏览器忽略缓存,因为这是另一个URL。 看一下这个帖子: https://bugs.chromium.org/p/chromium/issues/detail?id=409090

Firefox和其他浏览器没有这个问题。

答案 1 :(得分:2)

由于高速缓存条目键是目标URI,因此描述的行为似乎合乎逻辑(请参见7234 Hypertext Transfer Protocol (HTTP/1.1): Caching)。要解决此问题并有效使用缓存,您需要使图像托管服务器在两种情况下都给出相同的响应。

一种选择是使用户代理也在第一个请求中发送Origin HTTP标头(假定键targetUri的响应已经不在缓存中):

<img src="targetUri" crossorigin="anonymous" />

另一种选择是将映像托管服务器配置为发送CORS相关的HTTP标头,而不管请求是否包含Origin HTTP标头。有关更多信息,请参见S3 CORS, always send Vary: Origin关于StackOverflow的讨论。

您还可以使用Origin响应HTTP标头,通知用户代理响应对Vary请求HTTP标头敏感。不利之处在于,用户代理可能仅将Vary头用作响应验证器(而不用作高速缓存条目键的一部分),并且仅存储目标URI的单个响应实例,这使得更难以有效使用高速缓存。有关更多信息,请查看Mark Nottingham的The State of Browser Caching, Revisited文章。

答案 2 :(得分:0)

您正在应用哪些CORS设置? This post建议AllowedOrigin中的通配符解析(而不是逐字发送,这似乎是未记录的行为);然后缓存Access-Control-Allow-Origin标头值以用于后续请求,从而导致类似于您报告的问题。