Safari中的跨源资源共享策略拒绝跨域重定向

时间:2016-11-21 01:14:38

标签: safari cors

我们有一个重定向到另一台服务器的api端点。它通过XHR调用,并且在大多数浏览器中都可以正常工作,除了Safari(特别是在iOS上)。

我在控制台中遇到的错误是: 跨源资源共享策略拒绝跨域重定向

我们在执行重定向的页面上和其他服务器上有CORS。重定向页面设置:

Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: false

另一台服务器有:

Access-Control-Allow-Origin: *

如何在CORS策略中允许重定向?

7 个答案:

答案 0 :(得分:9)

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应用程序,您可以将其附加到报告中。运行它的步骤:

  1. 将“127.0.0.1 domain-a domain-b domain-c”添加到/etc/hosts
  2. 将以下代码放入corsredirect.py
  3. 在终端

    中运行这些命令
     virtualenv -p python3 venv
     . venv/bin/activate
     pip install cherrypy
     python corsredirect.py
    
  4. 将浏览器指向http://domain-a:8080并按下按钮

  5. 有应用程序。

    #!/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)
    

答案 1 :(得分:1)

您需要设置“Access-Control-Allow-Methods”标题。

Access-Control-Allow-Methods: *

答案 2 :(得分:1)

我遇到了在Heroku应用上托管我的API的类似问题。在Chrome和Firefox上,来自其他域的对我的API的请求工作得很好,但在Safari上,我遇到了令人沮丧的跨越源重定向被跨域资源共享策略拒绝了#34;。

经过一番研究后,似乎Safari中可能有一个bug阻止了一些使用CORS的重定向。我通过直接(myapp.herokuapp.com/api)而不是我的域(mydomain.com/api)请求Heroku应用程序来解决这个问题。

如果您的设置中有重定向到您的API,请直接请求根域可能有所帮助。

答案 3 :(得分:1)

如果您可以更改您的网址,您可以尝试使用Apache上的代理传递配置。该呼叫看起来像是在同一个域上但不会。 https://httpd.apache.org/docs/current/fr/mod/mod_proxy.html

答案 4 :(得分:1)

你试过吗?

Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: "Origin, X-Requested-With, Content-Type, Accept"
Access-Control-Allow-Methods: *

如需更多检查:http://enable-cors.org/

答案 5 :(得分:0)

除了&#34;简单请求&#34;以外的任何其他内容,权威来源拒绝使用#34; Access-Control-Allow-Origin&#34;标题并要求您明确设置标题&#34; Access-Control-Allow-Headers&#34;。

以下是Mozilla states for "Simple request"

  

唯一允许的方法是:

     
      
  • GET
  •   
  • HEAD
  •   
  • POST
  •   
     

除了用户代理自动设置的标头(例如   连接,用户代理等),允许的唯一标头   手动设置是:

     
      
  • 接受
  •   
  • 接受语言
  •   
  • 内容的语言
  •   
  • 内容类型
  •   
     

Content-Type标头唯一允许的值是:

     
      
  • 应用程序/ x-WWW窗体-urlencoded
  •   
  • 的multipart / form-data的
  •   
  • 文本/纯
  •   

当您的请求未满足&#34;简单请求&#34;要求你可能属于"Preflighted Requests"

  

GET,HEAD或POST以外的方法。此外,如果使用POST来发送具有除application / x-www-form-urlencoded,multipart / form-data或text / plain之外的Content-Type的请求数据,例如,如果POST请求使用application / xml或text / xml向服务器发送XML有效负载,则该请求将被预检。

至于有资格的请求 -

  

重要说明:在响应凭证请求时,服务器必须指定域,并且不能使用通配符。 Access-Control-Allow-Origin:*

由于您没有提供来自您的网页和服务器的实际HTTP请求和响应,因此我必须做出一些假设。我假设您的网页已在域foo.example下加载,并且您的API位于相同的foo.example域下,并且您的&#34;其他&#34;服务器位于域bar.example上。

您可能需要设置自己的页面,以便向&#34;其他人提供重定向请求。带有这些标题的服务器:

Access-Control-Request-Method: GET, OPTIONS
Access-Control-Request-Headers: x-requested-with, Content-Type, CUSTOM-HEADER

然后你可能需要设置你的&#34;其他&#34;服务器响应选项请求:

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 :(得分:0)

在两台服务器上启用HTTPS已经解决了我的问题。