协慌网

登录 贡献 社区

Access-Control-Allow-Origin 标头如何工作?

显然,我完全误解了它的语义。我想到了这样的事情:

  1. 客户端从 http:// siteA 下载 javascript 代码 MyCode.js - 原点
  2. MyCode.js 的响应头包含Access-Control-Allow-Origin:http:// siteB ,我认为这意味着允许 MyCode.js 对站点 B 进行跨源引用。
  3. 客户端触发 MyCode.js 的一些功能,它们反过来向 http:// siteB 发出请求,尽管是跨源请求,但这应该没问题。

好吧,我错了。它根本不起作用。所以,我已经阅读了跨源资源共享,并尝试在 w3c 推荐中阅读跨源资源共享

有一件事是肯定的 - 我仍然不明白我应该如何使用这个标题。

我完全控制了站点 A 和站点 B. 如何启用从站点 A 下载的 javascript 代码以使用此标头访问站点 B 上的资源?

PS

我不想使用 JSONP。

答案

Access-Control-Allow-OriginCORS(跨源资源共享)头

当站点 A 尝试从站点 B 获取内容时,站点 B 可以发送一个Access-Control-Allow-Origin响应头来告诉浏览器该页面的内容可以访问某些来源。 ( 原点域,加上方案和端口号 。)默认情况下,站点 B 的页面不能被任何其他来源访问 ; 使用Access-Control-Allow-Origin标头为特定请求源的跨域访问打开了一扇门。

对于站点 B 希望对站点 A 可访问的每个资源 / 页面,站点 B 应为其页面提供响应头:

Access-Control-Allow-Origin: http://siteA.com

现代浏览器不会直接阻止跨域请求。如果站点 A 从站点 B 请求页面,则浏览器将实际获取网络级别上的请求页面并检查响应头是否将站点 A 列为允许的请求者域。如果站点 B 未指示允许站点 A 访问此页面,则浏览器将触发XMLHttpRequesterror事件并拒绝响应请求的 JavaScript 代码的响应数据。

非简单请求

在网络级别上发生的事情可能比上面解释的稍微复杂一些。如果请求是“非简单” 请求 ,则浏览器首先发送无数据 “预检”OPTIONS 请求,以验证服务器是否接受请求。任何一个(或两个)请求都是非简单的:

  • 使用除 GET 或 POST 之外的 HTTP 动词(例如 PUT,DELETE)
  • 使用非简单的请求标头; 唯一简单的请求标头是:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type (当它的值为application/x-www-form-urlencodedmultipart/form-datatext/plain

如果服务器使用适当的响应标头(非简单标头的Access-Control-Allow-Headers ,非简单动词的Access-Control-Allow-Methods )与非简单动词和 / 或非动词匹配,则响应 OPTIONS 预检 - simple 标头,然后浏览器发送实际请求。

假设站点 A 想要发送/somePage的 PUT 请求,并使用非简单的Content-Typeapplication/json ,浏览器将首先发送预检请求:

OPTIONS /somePage HTTP/1.1
Origin: http://siteA.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type

请注意,浏览器会自动添加Access-Control-Request-MethodAccess-Control-Request-Headers ; 你不需要添加它们。此 OPTIONS 预检获得成功的响应标头:

Access-Control-Allow-Origin: http://siteA.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type

发送实际请求时(在预检完成后),行为与处理简单请求的方式相同。换句话说,其预检成功的非简单请求被视为与简单请求相同(即,服务器仍必须再次发送Access-Control-Allow-Origin以用于实际响应)。

浏览器发送实际请求:

PUT /somePage HTTP/1.1
Origin: http://siteA.com
Content-Type: application/json

{ "myRequestContent": "JSON is so great" }

并且服务器发回一个Access-Control-Allow-Origin ,就像它对一个简单的请求一样:

Access-Control-Allow-Origin: http://siteA.com

有关非简单请求的更多信息,请参阅了解基于 CORS 的 XMLHttpRequest

跨域请求共享 - CORS (AKA 跨域 AJAX 请求)是大多数 Web 开发人员可能遇到的问题,根据 Same-Origin-Policy,浏览器限制安全沙箱中的客户端 JavaScript,通常 JS 无法直接与远程通信来自不同域的服务器。在过去,开发人员创建了许多棘手的方法来实现跨域资源请求,最常用的方法是:

  1. 使用 Flash / Silverlight 或服务器端作为 “代理” 与远程通信。
  2. 带填充的 JSON( JSONP )。
  3. 在 iframe 中嵌入远程服务器并通过 fragment 或 window.name 进行通信,请参阅此处

这些棘手的方法或多或少存在一些问题,例如 JSONP 可能会导致安全漏洞,如果开发人员只是 “评估” 它,而上面的#3,虽然它有效,但两个域之间应该建立严格的契约,它既不灵活也不优雅恕我直言:)

W3C 引入了跨源资源共享(CORS)作为标准解决方案,以提供安全,灵活和推荐的标准方法来解决此问题。

机制

从高层次我们可以简单地认为 CORS 是来自域 A 的客户端 AJAX 调用和域 B 上托管的页面之间的契约,典型的跨源请求 / 响应将是:

DomainA AJAX 请求标头

Host DomainB.com
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/json
Accept-Language en-us;
Accept-Encoding gzip, deflate
Keep-Alive 115
Origin http://DomainA.com

DomainB 响应头

Cache-Control private
Content-Type application/json; charset=utf-8
Access-Control-Allow-Origin DomainA.com
Content-Length 87
Proxy-Connection Keep-Alive
Connection Keep-Alive

我上面标记的蓝色部分是核心事实,“Origin” 请求标题 “指示跨源请求或预检请求源自的位置”,“Access-Control-Allow-Origin” 响应标头指示此页面允许来自远程请求 DomainA(如果值为 * 指示允许来自任何域的远程请求)。

正如我上面提到的,W3 建议浏览器在提交实际的跨域 HTTP 请求之前实现 “ 预检请求 ”,简而言之,它是一个 HTTP OPTIONS请求:

OPTIONS DomainB.com/foo.aspx HTTP/1.1

如果 foo.aspx 支持 OPTIONS HTTP 动词,它可能会返回如下所示的响应:

HTTP/1.1 200 OK
Date: Wed, 01 Mar 2011 15:38:19 GMT
Access-Control-Allow-Origin: http://DomainA.com
Access-Control-Allow-Methods: POST, GET, OPTIONS, HEAD
Access-Control-Allow-Headers: X-Requested-With
Access-Control-Max-Age: 1728000
Connection: Keep-Alive
Content-Type: application/json

仅当响应包含 “Access-Control-Allow-Origin” 并且其值为 “*” 或包含提交 CORS 请求的域时,通过满足此 mandtory 条件,浏览器将提交实际的跨域请求,并缓存结果在 “ Preflight-Result-Cache ” 中。

我在三年前写了关于 CORS 的博客: AJAX Cross-Origin HTTP 请求

问题有点太老了,无法回答,但我发布这个问题是为了将来对这个问题的任何参考。

根据这个 Mozilla 开发者网络文章,

当资源从不同的域或端口请求资源时,资源会发出跨源 HTTP 请求 ,而不是第一个资源本身所服务的资源。

在此输入图像描述

从所服务的HTML 页面 http://domain-a.com使得一个<img>的 SRC 请求http://domain-b.com/image.jpg
今天网络上的许多页面都加载了来自不同域的CSS 样式表图像脚本等资源(因此它应该很酷)。

同源政策

出于安全原因,浏览器限制从脚本内发起的 跨源 HTTP请求。
例如, XMLHttpRequestFetch遵循同源策略
因此,使用XMLHttpRequestFetch的 Web 应用程序只能向其自己的域发出HTTP 请求

跨源资源共享(CORS)

为了改进 Web 应用程序,开发人员要求浏览器供应商允许跨域请求。

跨源资源共享(CORS)机制为 Web 服务器提供跨域访问控制 ,从而实现安全的跨域数据传输。
现代浏览器在API 容器中使用CORS (例如XMLHttpRequestFetch )来降低跨源 HTTP 请求的风险。

CORS 如何工作( Access-Control-Allow-Origin标头)

维基百科

CORS 标准描述了新的 HTTP 标头,它为浏览器和服务器提供了一种仅在有权限时才能请求远程 URL 的方法。

尽管服务器可以执行某些验证和授权, 但浏览器通常负责支持这些标头并遵守它们所施加的限制。

  1. 浏览器使用Origin HTTP标头发送OPTIONS请求。

    此标头的值是为父页面提供服务的域。当来自http://www.example.com的页面尝试访问service.example.com的用户数据时,以下请求标头将发送到service.example.com

    来源: http//www.example.com

  2. service.example.com的服务器可能会响应:

    • Access-Control-Allow-Origin (ACAO)标头在其响应中指示允许哪些源站点。
      例如:

      Access-Control-Allow-Origin: http://www.example.com

    • 如果服务器不允许跨源请求,则为错误页面

    • Access-Control-Allow-Origin (ACAO)标头,带有允许所有域的通配符:

      Access-Control-Allow-Origin: *