解決 ionic 中的 CORS(跨域)

譯者注:本人翻譯功力有限,因此文中不免有翻譯不許確的地方,湊合看吧,牛逼的話你看英文版的去,完事兒歡迎回來指正交流(^_^)html

若是你經過 ionic serve 或者 ionic run 命令使用或 live reload 或者訪問過外部 API 結點,那麼你確定遇到過 CORS 問題,譬以下面這樣:git

XMLHttpRequest cannot load http://api.ionic.com/endpoint. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8100' is therefore not allowed access.

那麼問題來了,什麼是 CORS 呢?又是什麼致使了這個問題嘞?github

什麼是 CORS?

CORS=Cross origin resource sharing(跨域資源共享)web

origin 就是你如今正在看的主站,你如今訪問的是 http://ionicframework.com/blog/handling-cors-issues-in-ionic,那麼 origin 就是 ionicframework.comnpm

若是說咱們向 http://cors.api.com/api 發起一個 AJAX 請求,那麼 host origin 會由被瀏覽器自動列入CORS請求的 Orgin header 指定好了*(原文:Say we send an AJAX request to http://cors.api.com/api, your host origin will be specified by the Origin header that is automatically included for CORS requests by the browser. )* 因爲 ionicframework.comapi.com 的主機並不匹配,因此在一個HTTP OPTIONS請求報頭的 form 中咱們全部從 ionicframework.com 發起的訪問服務器資源的請求必修獲得服務器的受權。gulp

假如上面的請求出現錯誤(不被服務器容許),那麼咱們是沒法從服務器訪問到(api.com上的)資源的。api

讓咱們來看一下當你經過ionic serveionic runionic run -l來運行 app 的時候 origin 會是什麼。跨域

瀏覽器中的運行

當你運行 ionic serve 時發生了什麼呢?瀏覽器

  • 啓動了一個本地 web 服務器
  • 你的瀏覽器打開並定位到本地服務器地址

這讓你看着你的應用加載到你電腦上一個瀏覽器裏,地址是:http://localhost:8100(若是你選擇了 localhost的話)。服務器

你的 origin 就是 localhost:8100

任何的發送到其餘不是 localhost:8100 主機上的 AJAX 請求都會把localhost:8100做爲他的 origin,這就會致使必需要通過一個 CORS 預檢來看是否能夠訪問(非本機的)服務器資源。

設備上的運行

當你運行 ionic run 時發生了什麼呢?

  • app 全部的文件被拷貝到設備(或者模擬器)上。
  • app 運行起來,觸發手機/模擬器上的瀏覽器訪問已經被拷貝上去的文件,好比: file://some/path/www/index.html

由於你正在運行的 URI 是 file://,因此你的 origin 將不會存在,因此任何向外的請求都再也不須要 CORS 請求。

在設備使用 livereload 運行

當你運行 ionic run -l時又發生了什麼呢?

  • 啓動了一個本地服務器
  • app 運行起來,觸發手機/模擬器上的一個瀏覽器經過http://192.168.1.1:8100來運行文件(你的 本地 ip 多是其餘的)。

你的 origin 就會是 192.168.1.1:8100

任何一個發送到不是192.168.1.1:8100的服務器上的 AJAX 請求都會須要進行 CORS 預檢請求來看是否能夠訪問到該服務器上的資源。

在 ionic 中解決 CORS 問題

CORS 問題只有在咱們經過 ionic serve 或者 ionic run -l 來運行或測試應用的時候纔會遇到。

解決這個問題有兩個辦法:第一個,也是比較簡單的一個,就是在你的 API 服務器端容許全部的 origin,然而咱們並不能控制咱們訪問的全部的結點。咱們須要的是一個不指定origin的請求。

咱們能夠經過使用代理服務器來解決這個問題。咱們來看看 Ionic CLI 是怎樣提供了一個易配置的代理服務器的。

Ionic CLI代理服務器

關於代理的快速定義:

在計算機網絡中,代理服務器就是一個服務器(計算機系統或者應用程序),是客戶端發起的請求從其餘服務器尋求資源的中間橋樑。

原文:In computer networks, a proxy server is a server (a computer system or an application) that acts as an intermediary for requests from clients seeking resources from other servers.

咱們爲了避開 CORS 問題須要作的就是有一個代理服務器,能夠接收咱們的請求,想 API 結點發出一個新的請求,接收結點響應,以後反饋給咱們的應用,從而避開 CORS 問題。

Ionic CLI 就有給你提供一個代理服務器從而避開全部可能會遇到的 CORS 問題的能力。

因爲代理服務器向你的目標主機發起了一個新的請求,因此就不會再有 origin,也就再也不須要 CORS 了。要注意,在瀏覽器增長了 Origin header 是很重要的。

設置代理服務器

注意,這些設置只有經過ionic serveionic run -l 運行應用才須要

首先咱們須要在 ionic.project文件中設置咱們的代理,這會告訴咱們的 Ionic 本地服務器監聽這些地址,而後發送這些請求到咱們的目標地址上。

在咱們的應用中,當運行 serverun -l 時候,咱們須要把要訪問的結點地址替換成代理服務器的地址。

使用gulp任務的 replace 模塊來轉換出口地址會簡單一點。

建議的方法是設置一個 Angular Constant 來定位到咱們試圖代理的 API。

這就是咱們下面要採用的方法。咱們會同時設置一個 Angular Service 來從 API結點 獲取數據。

設置代理路徑

好比說咱們想要訪問 http://cors.api.com/api,但並不容許咱們來自 localhost的 origin。

代理的設置包括兩件事兒:在你本地 Ionic 服務器須要訪問的 path,最終須要訪問API的 proxyUrl

在你的 ionic.project 中像這樣設置:

{ "name": "proxy-example", "app_id": "", "proxies": [ { "path": "/api", "proxyUrl": "http://cors.api.com/api" } ] }

經過ionic serve啓動你的服務器。

像咱們上面指定的這樣,當你訪問 Ionic 服務器地址 http://localhost:8100/api 的時候,它會以你的名義訪問 http://cors.api.com/api

這樣,就不須要 CORS 了。

設置 Angular Constant

把你的 API結點設置成 Angular Constants是很是簡單的一件事兒。

下面咱們就來把API結點指定成爲咱們的代理 URL。

以後(發佈時候)咱們會把正式的地址做爲 constant。

angular.module('starter', ['ionic', 'starter.controllers', 'starter.services']) .constant('ApiEndpoint', { url: 'http://localhost:8100/api' }) // For the real endpoint, we'd use this // .constant('ApiEndpoint', { // url: 'http://cors.api.com/api' // })

設置好以後你就能像下面這樣在應用中引入ApiEndpoint依賴,隨意調用這個constant了。

設置Angular Service

angular.module('starter.services', []) //NOTE: We are including the constant `ApiEndpoint` to be used here. .factory('Api', function($http, ApiEndpoint) { console.log('ApiEndpoint', ApiEndpoint) var getApiData = function() { return $http.get(ApiEndpoint.url + '/tasks') .then(function(data) { console.log('Got some data: ', data); return data; }); }; return { getApiData: getApiData }; })

經過 Gulp 自動轉換地址

這個過程當中,咱們須要修改gulpfile.js來添加兩個任務:添加代理和移除代理。

首先安裝replace模塊 - npm install --save replace

// `npm install --save replace` var replace = require('replace'); var replaceFiles = ['./www/js/app.js']; gulp.task('add-proxy', function() { return replace({ regex: "http://cors.api.com/api", replacement: "http://localhost:8100/api", paths: replaceFiles, recursive: false, silent: false, }); }) gulp.task('remove-proxy', function() { return replace({ regex: "http://localhost:8100/api", replacement: "http://cors.api.com/api", paths: replaceFiles, recursive: false, silent: false, }); })

結語

本教程向你展現了一個解決經過ionic serveionic run -l命令運行應用時候遇到的 CORS 問題的方法。

咱們知道在ionic serveionic run -l之間轉換 API 結點地址的時候可能會是個麻煩,比較建議的方法是啓動一個 gulp 進程。

解決 CORS 問題最簡單的方法是讓 API 提供者容許全部的 hosts,而後這事兒有點兒不太現實。

使用 Angular constant 和 replace 模塊能夠給咱們一個避開 CORS 的折中的辦法。

若是你想看看完整的例子,能夠看看這個示例項目

這就是你須要訪問一個有 CORS 限制的 API 服務器時候須要瞭解的全部事兒了。

若是你還有什麼疑問、問題或者想法,請在下面評論,或者在 twittergithub 上聯繫咱們。

相關文章
相關標籤/搜索