2013/08/28

Sencha Touch AJAX 跨網域存取 (Cross Domain Request)

通常為了省麻煩,我們會把『提供網頁的 server』與『提供資料的 API server』放在同一個網域下,除非是存取第三方的 server,但現在大多走 OAuth 配合 token 在做存取...


那為何我會遇到跨網域問題?

是這樣的,使用 PhoneGap 開發 app 時,若要跟 API server 要資料也屬於跨網域存取,不過 PhoneGap 的 webkit 設計不像我們平常在用的 browser,所以不會有此限制。

只是開發過程我們會直接利用 browser debug,不會每次都把網頁放到 PhoneGap 內,然後 build、deploy 到 mobile device... 這實在太花時間了,這就是為何我需要解決 cross domain 的原因。


先來看看直接存取會發生什麼事:
這是一個基本的 AJAX request,POST 帳號密碼做登入的動作
Ext.Ajax.request({
    url: 'http://api.example.com/login.php',
    params: {
        username: 'sylar',
        password: '123456'
    },
    success: function(response, opts) {
        console.log(response.responseText);
    },
    failure: function(response, opts) {
        console.log('server-side failure with status code ' + response.status);
    }
});

於是瀏覽器 console 出現錯誤訊息:
  • OPTIONS http://api.example.com/login.php?_dc=1377654028515 Origin http://localhost is not allowed by Access-Control-Allow-Origin.
  • XMLHttpRequest cannot load http://api.example.com/login.php?_dc=1377654028515. Origin http://app.localhost is not allowed by Access-Control-Allow-Origin.
跨網域存取時,browser 會先使用 HTTP OPTIONS method 詢問 server 是否允許這樣的 request,由於沒有得到正確的回應,browser 終止存取。


解法一:修改瀏覽器執行方式

這也是最快的方法
Windows
chrome.exe --disable-web-security

MacOS
open -a Google\ Chrome --args --disable-web-security


解法二:Server 回應特定 header

也就是允許任何來源
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
不過會發現有個缺點,就是每次 GET / POST 時,browser 總是會先發送 OPTIONS 詢問 server,造成頻寬浪費,可以在 Ajax.request 加入下列的參數就可避免
useDefaultXhrHeader: false


Cookie 無法儲存?

由於我的 server 認證方式是使用 session,也就是登入成功後,server 會使用 set-cookie 的方式要求 browser 把 session key 存在 cookie 內,不過上述方法並無法儲存 cookie。

解決的方式就是在 Ajax.request 加入參數
withCredentials: true

而 server 也必須明確指定允許的來源位址,不能用 wildcard (*),再來是 Access-Control-Allow-Credentials 值要為 true
Access-Control-Allow-Origin: http://localhost
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Credentials: true

以上就是跨網域存取,server / client 要做的修改,更多關於 Sencha Touch Ajax 的用法請參考官網的 Guideline:Using AJAX - Touch 2.2.1 - Sencha Docs


參考資料
javascript - Ext.Ajax.request sending OPTIONS request cross-domain when jQuery.ajax sends GET - Stack Overflow
ajax - Cookies not saved in Sencha Touch 2 - Stack Overflow


沒有留言:

張貼留言