Safari 中的跨域资源共享策略拒绝了跨域重定向
Posted
技术标签:
【中文标题】Safari 中的跨域资源共享策略拒绝了跨域重定向【英文标题】:Cross-origin redirection denied by Cross-Origin Resource Sharing policy in Safari 【发布时间】:2017-04-04 08:00:13 【问题描述】:我们有一个重定向到另一个服务器的 api 端点。它通过 XHR 调用,似乎在大多数浏览器中都能正常工作,除了 Safari(特别是在 ios 上)。
我在控制台中遇到的错误是: 跨域资源共享策略拒绝跨域重定向
我们在执行重定向的页面和另一台服务器上都有 CORS。重定向页面设置:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: false
另一台服务器有:
Access-Control-Allow-Origin: *
如何在 CORS 策略中允许重定向?
【问题讨论】:
如果跨域 XHR 在其他浏览器中工作但在 Safari 中不起作用,这听起来像是 Safari 中的一个错误,使其不符合fetch.spec.whatwg.org 中指定的当前 CORS 要求。所以请考虑在bugs.webkit.org 提交错误 这可能是 Safari 的一个错误,但我希望有一个解决方法。 查看***.com/questions/5750696/… 谢谢,但似乎没有提到任何工作。 请参考此链接***.com/questions/16824661/…。希望能帮助到你。我在 ASP .net 网站上遇到了同样的问题。我们当时无法解决。 【参考方案1】:W3C 规范和其他权威来源直接禁止通配符Access-Control-Allow-Origin
与Access-Control-Allow-Credentials: true
一起使用。
注意:字符串“*”不能用于支持凭据的资源。
https://www.w3.org/TR/cors/#resource-requests
重要提示:在响应凭证请求时,服务器必须指定域,并且不能使用通配符。
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials
如果凭据模式为“包含”,则
Access-Control-Allow-Origin
不能为*
。
https://fetch.spec.whatwg.org/#cors-protocol-and-credentials
进一步的步骤
由于您的问题缺乏细节,我们来做一些定义:
domain-a 是您的客户端代码的域 domain-b 是您发出请求的端点的域 domain-c 是请求最终重定向到的域首先,我认为,您想制定一个解决方法。只要您告诉所有端点都在您的控制之下,那么您可以:
从 domain-a 向 domain-c 发出直接请求(如果重定向取决于参数,甚至发出条件请求) 在您的后端公开另一个端点,该端点将请求包装到 domain-b如果确实违反规范,向WebKit tracker 报告错误也很重要。为了更容易重现这个案例,我制作了一个 CherryPy 应用程序,您可以将其附加到报告中。运行步骤:
-
将“127.0.0.1 domain-a domain-b domain-c”添加到您的
/etc/hosts
将以下代码放入corsredirect.py
在终端中运行这些命令
virtualenv -p python3 venv
. venv/bin/activate
pip install cherrypy
python corsredirect.py
将浏览器指向http://domain-a:8080并按下按钮
有应用程序。
#!/usr/bin/env python3
'''
Add localhost aliases in /etc/hosts for "domain-a", "domain-b", "domain-c".
The flow is: [domain-a] --CORS-GET--> [domain-b] --redirect--> [domain-c].
Open as http://domain-a:8080/
'''
import cherrypy
def cors():
cherrypy.response.headers['Access-Control-Allow-Origin'] = '*'
cherrypy.tools.cors = cherrypy._cptools.HandlerTool(cors)
class App:
@cherrypy.expose
def index(self):
return '''<!DOCTYPE html>
<html>
<head>
<meta content='text/html; charset=utf-8' http-equiv='content-type'>
<title>CORS redirect test</title>
</head>
<body>
<button>make request</button>
<script type='text/javascript'>
document.querySelector('button').onclick = function()
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://domain-b:8080/redirect', true);
xhr.onload = function()
var text = xhr.responseText;
console.log('success', text);
;
xhr.onerror = function()
console.error('failure');
;
xhr.send();
;
</script>
</body>
</html>
'''
@cherrypy.expose
@cherrypy.config(**'tools.cors.on': True)
def redirect(self):
raise cherrypy.HTTPRedirect('http://domain-c:8080/endpoint')
@cherrypy.expose
@cherrypy.config(**'tools.cors.on': True)
@cherrypy.tools.json_out()
def endpoint(self):
return 'answer': 42
if __name__ == '__main__':
config =
'global' :
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8
cherrypy.quickstart(App(), '/', config)
【讨论】:
我也用Access-Control-Allow-Credentials: false
尝试过,但它不能解决这个问题。在我的生产代码中,我已经将此设置为 false。
@Noodles 明确指出 Access-Control-Allow-Credentialsy value is not the problem, tou might want to consider updating the example code in the question to use
Access-Control-Allow-Credentials: false` 并且不使用 Access-Control-Allow-Credentials: true
。因为它是一个错误。
@Noodles 我已经更新了我的答案。您能否验证 Safari 是否在应用程序中失败了请求?【参考方案2】:
在两台服务器上启用 HTTPS 为我解决了这个问题。
【讨论】:
【参考方案3】:我在 Heroku 应用上托管我的 API 时遇到了类似的问题。在 Chrome 和 Firefox 上,来自另一个域的对我的 API 的请求运行良好,但在 Safari 上,我得到了令人沮丧的“跨域资源共享策略拒绝了跨域重定向”。
经过一些研究,Safari 中似乎有一个 bug 可以防止使用 CORS 进行一些重定向。我可以通过直接请求 Heroku 应用程序 (myapp.herokuapp.com/api
) 而不是我的域 (mydomain.com/api
) 来解决这个问题。
如果您的设置中有指向 API 的重定向,则直接请求根域可能会有所帮助。
【讨论】:
【参考方案4】:如果您可以更改您的网址,您可以尝试在您的 Apache 上使用代理通行证配置。呼叫看起来像在同一个域上,但它不会。 https://httpd.apache.org/docs/current/fr/mod/mod_proxy.html
【讨论】:
【参考方案5】:对于“简单请求”以外的任何内容,权威来源拒绝“Access-Control-Allow-Origin”标头的通配符,并要求您明确设置标头“Access-Control-Allow-Headers”。
这是Mozilla states for "Simple request":
唯一允许的方法是:
获取 头 发布除了由用户代理自动设置的标题(例如 Connection、User-Agent 等),唯一允许的标头 需要手动设置的是:
接受 接受语言 内容-语言 内容类型Content-Type 标头的唯一允许值是:
application/x-www-form-urlencoded 多部分/表单数据 文本/纯文本
当您的请求不符合“简单请求”要求时,您可能属于"Preflighted Requests"。
GET、HEAD 或 POST 以外的方法。此外,如果 POST 用于发送 Content-Type 不是 application/x-www-form-urlencoded、multipart/form-data 或 text/plain 的请求数据,例如如果 POST 请求使用 application/xml 或 text/xml 将 XML 有效负载发送到服务器,则请求被预检。
关于凭证请求 -
重要提示:在响应凭据请求时,服务器必须指定域,并且不能使用通配符。访问控制允许来源:*
由于您没有提供来自您的页面和服务器的实际 HTTP 请求和响应,我将不得不做出一些假设。我假设您的页面在域 foo.example 下加载,并且您的 API 在同一个 foo.example 域下,并且您的“其他”服务器在域 bar.example 上。
您可能需要设置您的页面以使用这些标头向“其他”服务器发出重定向请求:
Access-Control-Request-Method: GET, OPTIONS
Access-Control-Request-Headers: x-requested-with, Content-Type, CUSTOM-HEADER
然后您可能需要设置您的“其他”服务器以响应选项请求:
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: GET, OPTIONS
Access-Control-Allow-Headers: x-requested-with, Content-Type, CUSTOM-HEADER
那么你的页面应该能够完成请求。
【讨论】:
【参考方案6】:你试过了吗?
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: "Origin, X-Requested-With, Content-Type, Accept"
Access-Control-Allow-Methods: *
更多检查:http://enable-cors.org/
【讨论】:
【参考方案7】:您需要设置“Access-Control-Allow-Methods”标头。
Access-Control-Allow-Methods: *
【讨论】:
很遗憾,这并没有解决问题以上是关于Safari 中的跨域资源共享策略拒绝了跨域重定向的主要内容,如果未能解决你的问题,请参考以下文章