Ionic_解決項目中的跨域問題

ionic項目中,如果你使用ionic serve或者ionic run,并且開啟了動態(tài)加載(live reload),且訪問了遠端服務(wù)器的API,那么你就可能會遇到 跨域資源共享(CORS) 問題。出現(xiàn)類似下面的錯誤提示:

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? 為什么在這里會發(fā)生這個錯誤呢?

什么是CORS?

CORS = Cross origin resource sharing 跨域資源共享
origin是你當前所在頁面的主機地址。
如果你在瀏覽http://ionicframework.com/blog/handling-cors-issues-in-ionic頁面,它的origin就是ionicframework.com。在此頁面上,如果你要向http://cors.api.com/api發(fā)送一個AJAX請求,您的主機源將由Origin標頭指定,該標頭會自動包含在瀏覽器的CORS請求中。因為ionicframework.com和主機api.com并不匹配,我們從ionicframework.com的請求必須要經(jīng)過服務(wù)器的批準,才能夠訪問該資源,以Http Options請求頭的形式。

如果我們遇到了上面的錯誤,說明服務(wù)器沒有給我們的地址ionicframework.com賦予訪問該資源的權(quán)限。

下面來看一下,當通過ionic serve,ionic run,ionic run -l三種不同方式運行app時,你的origin分別是什么?

在瀏覽器中運行時

在執(zhí)行ionic serve時,發(fā)生了什么?

  • 啟動了一個本地web服務(wù)器
  • 你的瀏覽器自動打開了指向本地服務(wù)器地址的一個頁面

這時你可以看到你的app加載到了你的瀏覽器上,地址是http://localhost:8100(如果你選擇了localhost)。

這時,你的originlocalhost:8100。

任何發(fā)送到主機而不是localhost:8100的AJAX請求,都將以localhost:8100作為其origin,因此需要經(jīng)過CORS預(yù)檢請求,來查看是否有權(quán)限訪問該資源。

在設(shè)備上運行時

當執(zhí)行ionic run時,又發(fā)生了些什么呢?

  • 應(yīng)用程序文件被復(fù)制到設(shè)備(或模擬器)。
  • app開始運行,然后啟動一個設(shè)備(或模擬器)上的瀏覽器來打開這些文件,類似file://some/path/www/index.html

這樣,你的origin將不存在了,因為你正在運行于一個文件(file://)URI。理所當然,你的任何向外請求將不需要通過CORS預(yù)檢。

在設(shè)備上通過自動加載(livereload)運行時

執(zhí)行ionic run -l時,又將發(fā)生什么呢?

  • 首先啟動一個本地web服務(wù)器
  • 設(shè)備(或模擬器)上app開始運行,啟動一個瀏覽器來開地址http://192.168.1.1:8100(你的本地IP地址)上的文件。

這時,你的origin192.168.1.1:8100。

任何發(fā)送到主機而不是192.168.1.1:8100的AJAX請求,都將以192.168.1.1:8100作為其origin,因此需要經(jīng)過CORS預(yù)檢請求,來查看是否有權(quán)限訪問該資源。

在Ionic中處理CORS問題

CORS問題僅僅發(fā)生在,當我們以ionic serveionic run -l來運行或測試app的時候。

有2種方法來解決這個問題.

第一種,比較容易的方法,是設(shè)置遠端服務(wù)器,讓它可以接受所有源的請求。第二種,有時候我們沒有權(quán)限去修改遠端服務(wù)器,此時就需要一個不指定源的請求。

我們可以使用代理服務(wù)器來實現(xiàn)這個方案。ionic cli給我們提供了一個很方便的配置代理服務(wù)器的方法,下面我們看一下如何來實現(xiàn)。

Ionic CLI代理服務(wù)器

下面是關(guān)于代理(proxy)的一個定義:

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.

在計算機網(wǎng)絡(luò)中,代理服務(wù)器是一個客戶端請求的中介服務(wù)器(計算機系統(tǒng)或應(yīng)用),它用于幫助客戶端尋找位于其他服務(wù)器上的資源。

要解決我們在ionic中遇到的CORS問題,我們需要設(shè)置一個代理服務(wù)器,它接受我們的請求,并向API端點發(fā)出新的請求,然后接受響應(yīng),并將其轉(zhuǎn)發(fā)回我們的應(yīng)用程序。

由于代理服務(wù)器需要向目標發(fā)送新的請求,因此請求中將不會有origin(源),也就不再需要CORS了。 需要非常注意一點是,origin是瀏覽器自動幫我們添加在請求頭中的。

Ionic CLI具有為客戶端請求設(shè)置代理服務(wù)器的能力,用來幫助您解決CORS問題,下面來看一下Ionic CLI設(shè)置代理的方法。

設(shè)置代理服務(wù)器

再次說明一下,僅僅在ionic serveionic run -l的時候需要設(shè)置代理。

首先,我們需要在ionic.project(注意,ionic2 cli新版本已經(jīng)將此文件重命名為ionic.config.json)配置文件中設(shè)置代理。 這將告訴Ionic本地服務(wù)器監(jiān)聽這些路徑并將這些請求轉(zhuǎn)發(fā)到目標網(wǎng)址。

在app中,我們需要替換包含endpoint的URLS,并設(shè)置為我們的代理服務(wù)器地址。(In our app, we will need to replace our endpoint URLS to be set to the proxy server address for when we are running serve or run -l.)

什么是endpoint?

在項目中 endpoint有時也寫作baseUrl,比如這個http://cors.api.com/api/book/2/detail的endpoint是http://cors.api.com/api,再比如http://localhost:8101/api/user/123的endpoint是http://localhost:8101/api。

筆者沒有想到好的中文來替代這個英文單詞,所以沒有進行翻譯,希望小伙伴們能夠理解它的意思就好啦~~~~~

我們可以通過設(shè)置一些gulp任務(wù),用gulp中的替換模塊(replace)來替換出這些URLS,來簡化這一步驟。

比較推薦的方法是設(shè)置一個Angular Constant來同一設(shè)置的endpoint,方便統(tǒng)一進行修改和維護。

下面是操作步驟。我們需要設(shè)置一個Angular Service ApiEndpoint來獲取數(shù)據(jù)。

配置代理地址

配置代理有兩個需要注意的地方。

  • path:你在本地Ionic服務(wù)器上訪問它們的路徑
  • proxyUrl:你最終希望通過API調(diào)用達到的proxyUrl

修改ionic.config.json(舊版本Ionic CLI是ionic.project):

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

如上所述,當您請求訪問http://localhost:8100/api的ionic服務(wù)器時,它會替你代理請求到http://cors.api.com/api上。這樣,就不需要CORS了。

設(shè)置Angular Constant

很容易將你的ApiEndpoint設(shè)置為Angular Constant。下面,我們已經(jīng)將ApiEndpoint指定為我們的代理url。然后,我們就可以使用這個url作為一個常數(shù)。

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'
// })

設(shè)置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實現(xiàn)URL自動切換(可選)

(這是可選的,如果你使用手動配置就不需要gulp自動配置了)

首先,需要安裝replace module

npm install --save replace

然后,我們需要修改gulpfile.js,并添加2個任務(wù),來添加代理地址、移出代理地址。

// `npm install --save replace`
var replace = require('replace');
//注意下面的文件地址,它是包含你endpoint或baseurl的文件
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,
  });
})

結(jié)束語

這個教程展示給你了在運行ionic serveionic run -l的時候,一個處理CORS問題的方法。

我們知道,如果按這個方法處理,當我們需要在ionic serveionic run -l切換的時候,將ApiEndpoint替換出來可能會比較麻煩。因此我們推薦使用gulp在程序啟動時自動完成這個過程。

其實,最簡單的處理CORS問題的方法,是要求你的api提供服務(wù)器來允許所有的origin。但是,有時候我們無法這么做。

使用Angular Constant和replace module會給我們一個愉快的解決方法來處理CORS問題。

如果你需要一個具體的例子,可以看一下這個示例工程

上面說的就是所有的當你訪問一個API服務(wù)器時,關(guān)于處理CORS問題的全部。

作者:ten5743
鏈接:http://www.itdecent.cn/p/2b955fd32a45
來源:簡書

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在ionic項目中,如果你使用ionic serve或者ionic run,并且開啟了動態(tài)加載(live relo...
    ten5743閱讀 12,935評論 4 26
  • 本方法已棄用,請參考新方法 ionic 3 開發(fā)環(huán)境切換 ionic 優(yōu)雅的解決開發(fā)跨域及后臺環(huán)境切換 之前主要接...
    凌音同學(xué)閱讀 1,399評論 0 8
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,534評論 19 139
  • 1. 什么是跨域 跨域,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。它是由瀏覽器的同源策略造成的,是瀏覽器對JavaScri...
    cbw100閱讀 6,480評論 2 86
  • 今天打車遇到一個魔方司機,讓我印象很深刻 我剛上車司機就對我一笑,讓我覺得這司機跟一般的司機有些不一樣。同時他的微...
    5765f3fa240e閱讀 492評論 1 0

友情鏈接更多精彩內(nèi)容