ionic 優(yōu)雅的解決開發(fā)跨域及后臺環(huán)境切換

本方法已棄用椭懊,請參考新方法 ionic 3 開發(fā)環(huán)境切換

ionic 優(yōu)雅的解決開發(fā)跨域及后臺環(huán)境切換

之前主要接觸的是AndroidJ2EE之類的開發(fā),不是一個正統(tǒng)前端狗,所以很多前端的特性和騷操作都沒有深入了解過。去年部門開始要我?guī)ь^入坑ionic2,于是我從一個連JavaScriptHello World都沒寫過的人雾消,轉(zhuǎn)型為一個Angualr 2+ionic 2的偽前端狗灾搏。由于沒人指導(dǎo)挫望,期間踩坑無數(shù),的感覺頭發(fā)日漸稀少狂窑,炎熱的夏天媳板,頭頂總是有絲絲涼意。所以現(xiàn)在閑了下來(更應(yīng)該說是頓悟后打雞血般的興奮感以及女朋友的支持……)泉哈,決定把一些遇到的坑寫出來蛉幸。

-1

我是前端入門小白,所以可能這條路是錯的丛晦,不喜勿噴奕纫。

0x00 開始

后面都圍繞著Gank.io這個網(wǎng)站提供的API測試。

ionic其實就是一個基于Angular前端項目烫沙。所以在前端開發(fā)的過程中匹层,必須要解決CORS跨域問題。解決方法主要有兩個:

  1. Chrome瀏覽器中安裝Access-Control-Allow-OriginChrome拓展
  2. 修改后臺Service,允許跨域訪問(非常極其以及十分的不安全锌蓄,但我 TMD 前面兩個項目就是這樣做的升筏,而且因為項目問題,現(xiàn)在不能隨便更改項目配置瘸爽,只能眼睜睜開著項目裸奔著您访,這或許是我這輩子最大的敗筆吧)
  3. 使用ionic CLI代理服務(wù)器

為何不用第一種方法?

裝完Chrome拓展后剪决,開啟拓展后灵汪,默認(rèn)所有網(wǎng)站都允許跨域,這就很不安全了 柑潦。

這方法還存在一個坑享言,就是開啟拓展后,上Gayhub Star 一些屌炸天的項目的時候妒茬,居然會報錯担锤,一兩次沒注意,以為是梯子不穩(wěn)了乍钻,一直錯誤肛循,才感覺好像并沒有那么簡單。經(jīng)過一番推理银择,發(fā)現(xiàn)就是因為開啟了跨域拓展多糠,Gayhub做了保護,拒絕了請求浩考,導(dǎo)致報錯

當(dāng)然夹孔,一定要用這方法也不是不行,就要花點心思配置了,一個項目還好搭伤,多個項目就麻煩了只怎,而且這拓展有時候還會莫名的失效,需要開關(guān)拓展刷新頁面才恢復(fù)正常怜俐,這就很不優(yōu)雅了身堡。

為何不用第二種方法?

f**k


為何用第三種方法拍鲤?

因為這合理切符合我們對優(yōu)雅的追求贴谎。

0x01 設(shè)置ionic CLI代理服務(wù)器

ionic 2ionic 3項目根目錄中,都有ionic.config.json這個文件季稳,我們就是通過這個配置文件實現(xiàn)的擅这。

實現(xiàn)代理

現(xiàn)在我們要調(diào)用API接口http://www.gank.io/api/day/history,獲取所有歷史記錄景鼠。我們來拆解下這個URL:
通過API說明頁:

  • 這個網(wǎng)站的主URLhttp://gank.io
  • 所有接口都是/api這個路由下的

專業(yè)一點的說法就是仲翎,這個項目的endpointhttp://www.gank.io/api,path/api
說點人話就是铛漓,如果我是http://www.gank.io網(wǎng)頁中包含的一個ajax請求谭确,當(dāng)我請求/api/history這個url的時候,瀏覽器最終會把你的請求地址補全票渠,補全為http://www.gank.io/api/day/history,然后你就可以得到數(shù)據(jù)了芬迄。你要實現(xiàn)這自動補全(瞎稱呼的问顷,為了方便理解)URL的功能,必須要以/api開頭禀梳,當(dāng)瀏覽器發(fā)現(xiàn)是/api開頭的時候杜窄,就會自動補全,如果不是算途,就直接請求你輸入的URL了塞耕。可以把這理解為規(guī)定嘴瓤,沒有為什么扫外。
結(jié)論:

  • proxyUrl=>http://gank.io/api
  • path=>/api

修改ionic.config.json文件:

{
    "name": "gank-me",
    "app_id": "",
    "type": "ionic-angular",
    "integrations": {},
    "proxies": [
        {
            "path": "/api",
            "proxyUrl": "http://gank.io/api"
        }
    ]
}

測試

import { Http } from '@angular/http';
//***

this.http.get("/api/day/history")
      .toPromise()
      .then(res=>{debugger});

結(jié)果:
就是成功的返回數(shù)據(jù)嘛

0x02優(yōu)雅的切換服務(wù)器環(huán)境

一個稍微正經(jīng)點的商業(yè)項目,總有至少3個環(huán)境情況廓脆,開發(fā)筛谚、測試、生產(chǎn)(正式)環(huán)境,即Dev,UAT,Prod停忿。在不同環(huán)境下驾讲,我們有不一樣的配置,如數(shù)據(jù)庫的文件名不同,某些服務(wù)用到的key不同………這就需要在各個環(huán)境之間進行切換吮铭。切換的方式有兩種:

  • 在一個*.ts文件中时迫,定義好URL,Key等信息,測試谓晌、打包時掠拳,手動切換
  • 通過Webpack腳本,通過參數(shù)的方式切換

為何放棄方法一扎谎?

放棄主要是誤操作概率太高碳想,且難以接入Jenkins自動構(gòu)建打包犁柜。如果沒有一個人專門負(fù)責(zé)打包铐尚,且這個人還有自己的一個打包TODO list,很容易想象這樣一個場景较沪,經(jīng)過漫長的打包過程后预吆,安裝到手機時龙填,才發(fā)現(xiàn)環(huán)境錯了,這就很僵硬了拐叉;當(dāng)然還有比這更糟糕的岩遗,就是在生產(chǎn)環(huán)境一頓猛如虎的操作后才發(fā)現(xiàn),丫喲凤瘦,環(huán)境錯了K藿浮!

方法二蔬芥?

如果是通過參數(shù)傳入的方式更改環(huán)境梆靖,或許會簡單準(zhǔn)確很多吧,至少在Android開發(fā)時笔诵,通過多渠道打包的方式打包返吻,沒有出現(xiàn)過環(huán)境搞錯的問題。所以這方法二就顯得很正確乎婿,很優(yōu)雅了测僵。那么如何實現(xiàn)呢?

開始

預(yù)配置環(huán)境參數(shù)

創(chuàng)建三個環(huán)境對應(yīng)的ts文件:

  • environment.dev.ts
  • environment.prod.ts
  • environment.uat.ts

結(jié)構(gòu):

.
├── src
│   ├── environments
│   │   ├── environment.dev.ts
│   │   ├── environment.prod.ts
│   │   └── environment.uat.ts

environment.prod.ts為例谢翎,內(nèi)容如下:

export const ENV = {
    "mode": "Prod",
    "database": "data.db",
    "cordova": {
        "id": "io.ionic.starter",
        "version": "0.0.1",
        "ios": {
            "CodePushServerUrl": "prod",
            "CodePushDeploymentKey": "1234567890"
        },
        "android": {
            "CodePushServerUrl": "prod",
            "CodePushDeploymentKey": "0987654321"
        }
    }
}

然后在項目根目錄中創(chuàng)建文件夾config捍靠,里面創(chuàng)建文件webpack.config.js

.
├── config
│   └── webpack.config.js

內(nèi)容如下:

var chalk = require("chalk");
var fs = require('fs');
var path = require('path');
var useDefaultConfig = require('@ionic/app-scripts/config/webpack.config.js');

var env = process.env.NODE_ENV || 'dev';
var IONIC_ENV = process.env.IONIC_ENV

console.log('NODE_ENV:' + env);

console.log('IONIC_ENV:' + IONIC_ENV);

if (env === 'dev') {
  if (IONIC_ENV == 'dev') {
    useDefaultConfig.dev.resolve.alias = {
      "@env/environment": path.resolve(environmentPath('dev'))
    };
  };
  if (IONIC_ENV == 'prod') {
    useDefaultConfig.prod.resolve.alias = {
      "@env/environment": path.resolve(environmentPath('dev'))
    };
  };
}

if (env === 'uat') {
  if (IONIC_ENV == 'dev') {
    useDefaultConfig.dev.resolve.alias = {
      "@env/environment": path.resolve(environmentPath('uat'))
    };
  };
  if (IONIC_ENV == 'prod') {
    useDefaultConfig.prod.resolve.alias = {
      "@env/environment": path.resolve(environmentPath('uat'))
    };
  };
}

if (env === 'prod') {
  if (IONIC_ENV == 'dev') {
    useDefaultConfig.dev.resolve.alias = {
      "@env/environment": path.resolve(environmentPath('prod'))
    };
  };
  if (IONIC_ENV == 'prod') {
    useDefaultConfig.prod.resolve.alias = {
      "@env/environment": path.resolve(environmentPath('prod'))
    };
  };
}

function environmentPath(env) {
  var filePath = 'src/environments/environment.' + env + '.ts';
  console.log("use env file:" + filePath);
  if (!fs.existsSync(filePath)) {
    console.log(chalk.red('\n' + filePath + ' does not exist!'));
  } else {
    return filePath;
  }
}

module.exports = function () {
  return useDefaultConfig;
};

修改項目的package.json文件,添加:

"config": {
    "ionic_webpack": "./config/webpack.config.js"
}

修改tsconfig.json

{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@env/environment": [
        "environments/environment.prod"
      ]
    }
  }
}

實現(xiàn)動態(tài)切換環(huán)境URL

前面我們說了設(shè)置ionic CLI代理岳服,這時候當(dāng)然也要加入剂公,實現(xiàn)一個命令,切換環(huán)境及參數(shù)吊宋,才是我們的目標(biāo)纲辽。下面我們開始實現(xiàn).

  1. 項目根目錄創(chuàng)建文件enviroment.json
{
    "devUrl": "http://localhost:8080/api",
    "devPath": "/api",
    "uatUrl": "http://r.example.com/api",
    "uatPath": "/api",
    "prodUrl": "http://gank.io/api",
    "prodPath": "/api"
}

devuat我瞎寫的颜武,不要在意,只是為了實現(xiàn)效果而已啦拖吼。

  1. 然后鳞上,我們修改剛剛的webpack.config.js文件,添加一個方法setProxy()及調(diào)用者方法的一句代碼吊档,完整的webpack.config.js:
var chalk = require("chalk");
var fs = require('fs');
var path = require('path');
var useDefaultConfig = require('@ionic/app-scripts/config/webpack.config.js');

var env = process.env.NODE_ENV || 'dev';
var IONIC_ENV = process.env.IONIC_ENV

console.log('NODE_ENV:' + env);

console.log('IONIC_ENV:' + IONIC_ENV);

if (env === 'dev') {
  if (IONIC_ENV == 'dev') {
    useDefaultConfig.dev.resolve.alias = {
      "@env/environment": path.resolve(environmentPath('dev'))
    };
  };
  if (IONIC_ENV == 'prod') {
    useDefaultConfig.prod.resolve.alias = {
      "@env/environment": path.resolve(environmentPath('dev'))
    };
  };
}

if (env === 'uat') {
  if (IONIC_ENV == 'dev') {
    useDefaultConfig.dev.resolve.alias = {
      "@env/environment": path.resolve(environmentPath('uat'))
    };
  };
  if (IONIC_ENV == 'prod') {
    useDefaultConfig.prod.resolve.alias = {
      "@env/environment": path.resolve(environmentPath('uat'))
    };
  };
}

if (env === 'prod') {
  if (IONIC_ENV == 'dev') {
    useDefaultConfig.dev.resolve.alias = {
      "@env/environment": path.resolve(environmentPath('prod'))
    };
  };
  if (IONIC_ENV == 'prod') {
    useDefaultConfig.prod.resolve.alias = {
      "@env/environment": path.resolve(environmentPath('prod'))
    };
  };
}

function environmentPath(env) {
  var filePath = 'src/environments/environment.' + env + '.ts';
  console.log("use env file:" + filePath);
  setProxy(env);
  if (!fs.existsSync(filePath)) {
    console.log(chalk.red('\n' + filePath + ' does not exist!'));
  } else {
    return filePath;
  }
}

function setProxy(env) {
  console.info("Set proxy");
  var configJson = require("../enviroment.json");
  fs = require('fs');
  var path = require('path');
  var filePath = path.resolve(__dirname, '../ionic.config.json');
  var m = JSON.parse(fs.readFileSync(filePath).toString());
  var serverUrl;
  var urlPath;
  switch (env) {
    case "prod":
      serverUrl = configJson.prodUrl;
      urlPath = configJson.prodPath;
      break;
    case "dev":
      serverUrl = configJson.devUrl;
      serverUrl = configJson.devPath;
      break;
    default:
      serverUrl = configJson.devUrl;
      serverPath = configJson.devPath;
      break;
  }
  m.proxies[0].proxyUrl = serverUrl;
  m.proxies[0].path = urlPath;
  fs.writeFileSync(filePath, JSON.stringify(m));
}

module.exports = function () {
  return useDefaultConfig;
};

添加啟動Script

現(xiàn)在其實已經(jīng)完成了配置文件的編寫篙议,下面就是解決如何使用的問題,我這里舉個不完整例子

  1. 修改package.json添加兩個環(huán)境,DevProd:

    {
      "scripts": {
        "clean": "ionic-app-scripts clean",
        "build": "ionic-app-scripts build",
        "lint": "ionic-app-scripts lint",
        "ionic:build": "ionic-app-scripts build",
        "ionic:serve": "ionic-app-scripts serve",
        "serve:uat": "NODE_ENV=uat ionic serve",
        "serve:prod": "NODE_ENV=prod ionic serve"
      }
    }
    
2. [例]在`home.ts`中調(diào)用配置的參數(shù)
    
    
    ```typescript
    
    import { Http } from '@angular/http';
    import { ENV } from '@env/environment'
    
    @IonicPage()
    @Component({
      selector: 'page-home',
      templateUrl: 'home.html',
    })
    export class HomePage {
    
      constructor(private http: Http) {
      }
    
      ionViewDidLoad() {
        console.log(ENV.mode);  //打印環(huán)境
        debugger;               //加個斷點
      }
    
    }
  1. 切換環(huán)境并運行
    假設(shè)需要切換到prod環(huán)境怠硼,那么終端執(zhí)行$ npm run serve:prod鬼贱,如果成功,會自動打開網(wǎng)頁
    斷點

    我們看到香璃,參數(shù)都在ENV這個對象中这难。
    ionic CLI代理就不測了,反正都可以用就對了葡秒。
    如果要切換uat那就$ npm run serve:uat唄姻乓,這些命令都是定義在package.jsonscripts里面,大家可以依葫蘆畫瓢整起來
  2. 完成

項目

Gank-me
參考allnew_package分支

引用

徹底解決Ionic項目中的跨域問題
ionic3 中使用 environments

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末眯牧,一起剝皮案震驚了整個濱河市蹋岩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌学少,老刑警劉巖剪个,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異版确,居然都是意外死亡禁偎,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門阀坏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人笆檀,你說我怎么就攤上這事忌堂。” “怎么了酗洒?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵士修,是天一觀的道長。 經(jīng)常有香客問我樱衷,道長棋嘲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任矩桂,我火速辦了婚禮沸移,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己雹锣,他們只是感情好网沾,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蕊爵,像睡著了一般辉哥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上攒射,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天醋旦,我揣著相機與錄音,去河邊找鬼会放。 笑死饲齐,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鸦概。 我是一名探鬼主播箩张,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼窗市!你這毒婦竟也來了先慷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤咨察,失蹤者是張志新(化名)和其女友劉穎论熙,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體摄狱,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡脓诡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了媒役。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祝谚。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖酣衷,靈堂內(nèi)的尸體忽然破棺而出交惯,到底是詐尸還是另有隱情,我是刑警寧澤穿仪,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布席爽,位于F島的核電站,受9級特大地震影響啊片,放射性物質(zhì)發(fā)生泄漏只锻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一紫谷、第九天 我趴在偏房一處隱蔽的房頂上張望齐饮。 院中可真熱鬧捐寥,春花似錦、人聲如沸沈矿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽羹膳。三九已至睡互,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間陵像,已是汗流浹背就珠。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留醒颖,地道東北人妻怎。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像泞歉,于是被迫代替她去往敵國和親逼侦。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容