缓存 Access-Control-Allow-Origin 值 cross-site

Caching of Access-Control-Allow-Origin value cross-site

我正在尝试编写一个 nginx 配置来处理 http 和 https 上的两个站点,只要客户端从不访问这两个站点,它似乎就可以工作,但如果他们这样做,就会出现 caching/cross-site 问题.

# Allow cross origin
location ~* \.(eot|svg|ttf|woff|woff2|json)$ {
    if ($http_origin ~* (https?://(admin\.)?example\.com(:[0-9]+)?)) {
        add_header 'Access-Control-Allow-Origin' "$http_origin";
    }
}

所以如果我加载 example.com,一切正常,但是当我加载管理员时。example.com 我遇到这样的问题

(index):1 XMLHttpRequest cannot load http://origin.example.com/js/data-lib/currency.json. The 'Access-Control-Allow-Origin' header has a value 'http:// example . com' that is not equal to the supplied origin. Origin 'http:// admin . example . com' is therefore not allowed access.

据我所知,这是因为浏览器缓存了带有 header 的原始请求,现在它拒绝了我,即使来自服务器的另一个请求允许它。证据是,如果我在 Chrome 开发人员工具中检查禁用缓存,那么问题就不会发生。

如何解决这个问题?是否可以在一个配置中执行多个域 + ssl/http,或者是否有必要根据请求的域和协议将其拆分?

(抱歉,我的示例中出现了可怕的空格,显然 Whosebug 认为我在编写示例时正在尝试 post 链接)

如果您添加 Vary 响应 header 和值 Origin,这应该会导致任何浏览器跳过其缓存并在Origin 请求的值 header 不同于它缓存的请求的 Origin 值。

参见 the relevant part of the HTTP spec。所以你可以更新你的 nginx 配置来做到这一点:

# Allow cross origin
location ~* \.(eot|svg|ttf|woff|woff2|json)$ {
    if ($http_origin ~* (https?://(admin\.)?example\.com(:[0-9]+)?)) {
        add_header 'Access-Control-Allow-Origin' "$http_origin";
    }
    add_header 'Vary' "Origin";
}

您可以在 the MDN article on the Vary response header 中阅读更多内容。

The Vary HTTP response header determines how to match future request headers to decide whether a cached response can be used rather than requesting a fresh one from the origin server. It is used by the server to indicate which headers it used when selecting a representation of a resource in a content negotiation algorithm.

…在 MDN Access-Control-Allow-Origin 文章的 CORS and caching 部分:

If the server sends a response with an Access-Control-Allow-Origin value that is an explicit origin (rather than the "*" wildcard), then the response should also include a Vary response header with the value Origin — to indicate to browsers that server responses can differ based on the value of the Origin request header.

…在the Fetch spec itself中:

If your requirements are more complicated than setting Access-Control-Allow-Origin to * or a static origin, use the Vary: Origin response header.

If Vary is not used and a server is configured to send Access-Control-Allow-Origin for a certain resource only in response to a CORS request: When a user agent receives a response to a non-CORS request for that resource, the response will lack Access-Control-Allow-Origin and the user agent will cache that response. If the user agent then encounters a CORS request for the resource, it will use that cached response from the previous non-CORS request — without Access-Control-Allow-Origin.

But if Vary: Origin is used in the same scenario, it will cause the user agent to fetch a response that includes Access-Control-Allow-Origin, rather than using the cached response from the previous non-CORS request lacking Access-Control-Allow-Origin