2016-11-21 182 views
8

我們有一個重定向到另一個服務器的api端點。它通過XHR調用,似乎在大多數瀏覽器中都能正常工作,除了Safari(特別是iOS)。由Safari中的跨源資源共享策略拒絕的跨源重定向

我得到在控制檯的錯誤是: 通過跨來源資源共享策略拒絕跨域重定向

我們有做重定向的頁面上,並在其他服務器上CORS。重定向頁面設置:

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

其他服務器有:

Access-Control-Allow-Origin: * 

我怎樣才能讓在CORS政策重定向?

+0

如果跨源XHR在其他瀏覽器中工作,但在Safari中不工作,這聽起來像是Safari中的一個錯誤,它使其不符合https://fetch.spec.whatwg.org/中指定的當前CORS要求。 。所以請考慮在https://bugs.webkit.org/ – sideshowbarker

+0

提交bug。這可能是Safari的一個bug,但我希望有一個解決方法。 – Noodles

+0

檢查這個http://stackoverflow.com/questions/5750696/how-to-get-a-cross-origin-resource-sharing-cors-post-request-working?rq=1 – nmanikiran

回答

1

您需要設置「Access-Control-Allow-Methods」標題。

Access-Control-Allow-Methods: * 
+0

不幸的是,這並沒有解決問題 – Noodles

1

我遇到了一個類似的問題,託管我的API在Heroku應用程序。在Chrome和Firefox上,來自另一個域的API請求運行良好,但在Safari上,我遇到了令人沮喪的「跨源資源共享策略拒絕的跨源重定向」。

經過一番研究,似乎在Safari中可能有一個bug,它阻止了一些CORS重定向。我可以通過直接申請Heroku應用程序(myapp.herokuapp.com/api)而不是我的域名(mydomain.com/api)來解決此問題。

如果您已經設置了重定向到API的設置,直接請求根域可能會有所幫助。

1

你試過了嗎?

Access-Control-Allow-Origin: * Access-Control-Allow-Headers: "Origin, X-Requested-With, Content-Type, Accept" Access-Control-Allow-Methods: * 爲多個校驗http://enable-cors.org/

6

W3C規範和其他權威來源與Access-Control-Allow-Credentials: true當用於直接禁止通配符Access-Control-Allow-Origin

注意:字符串「*」不能用於支持憑證的資源。

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

進一步的措施

因爲你的問題缺乏細節,讓我們做一些定義:

  • 域的一個是你的客戶端代碼域
  • 域-b是en的域dpoint那裏你也求
  • 域-C就是請求最終被重定向到

首先的領域,我想,你想一個解決辦法。只要你告訴所有的終點是你的控制之下,所以你可以:

  • 從做直接請求域的一個域-C(甚至使一個條件請求,如果重定向取決於參數)
  • 暴露出你的後端另一個端點包裝要求域-b

這也是很重要的一個缺陷報告給WebKit tracker如果真的違反了規範。爲了更容易地重現我創建CherryPy應用程序的情況,您可以將其添加到報告中。步驟來運行它:

  1. 加入 「127.0.0.1域的域-B域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並按下按鈕

有應用程序。

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

我也嘗試了'Access-Control-Allow-Credentials:false',但它沒有解決這個問題。在我的生產代碼中,我已將此設置設置爲false。 – Noodles

+0

@Noodles爲了說明'Access-Control-Allow-Credentialsy值不是問題,tou可能會考慮更新問題中的示例代碼以使用'Access-Control-Allow-Credentials:false'而不是使用'Access-Control-Allow-Credentials:true'。因爲這是一個錯誤。 – sideshowbarker

+0

謝謝,我已更新原始問題 – Noodles

0

對於只是多了一個「簡單的請求」以外的,權威的來源否認了「訪問控制允許來源」頭通配符,並要求你明確地設置頁眉「訪問控制允許-headers」。

這裏是Mozilla states for "Simple request"

只允許使用方法是:

  • GET
  • HEAD
  • POST

除了由自動設置的頭用戶代理(例如 連接,用戶代理,等等),其被允許 手動設置唯一標題有:

  • 接受
  • 接受語言
  • 內容語言
  • 內容類型

的爲Content-Type頭只允許值包括:

  • 應用程序/ x-WWW窗體-urlencoded
  • 的multipart/form-data的
  • text/plain的

當你的請求不符合 「簡單請求」 的要求,你可能陷入"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域下,並且你的「其他」服務器位於域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 

然後您的頁面應該能夠完成請求。

0

在兩臺服務器上啓用HTTPS已解決了我的問題。

相關問題