2018年4月11日 星期三

Serverless All-Star 參加筆記

前言

Serverless目前還沒有一個公認的定義,這個技術對於一個開發人員,可以專注於自己的程式,而不用去管網站架設、系統組態設定,只要將自己的程式碼丟上雲端就能完成應用程式部署、立即使用寫好的Web服務。在實務上我已經將一些供其他模組呼叫的核心程式變成Serverless架構,這樣的組件化除了降低整個開發成本外,也讓我能專注的監控這些核心的服務的使用情況,目前導入起來感覺挺好的。在 2018.03.29 參加了Serverless All-Star 這個活動,來學習看看有沒有其他沒想到的應用,感謝現場熱心的學員有開共筆,一起記錄講師的重點:

https://hackmd.io/PPFD5nkzRXOcA59h5jf2jg?both

DevOps & Serverless - 陳正瑋 / 得寬科技DevOps Engineer

Serverless 提供更高的彈性及擴展性,但別想得太沒好,引用 Patrick Debois 演講內容 〝Less is More”,看似少了很多工,但對於各種角色應該注意以下事項:

  • Dev 要注意debug和monitoring的問題
  • Ops 要注意latency問題
  • Sec 要注意pipeline傳輸安全問題
  • Boss 要注意是否真的能省的錢


極速 IT 架構新趨勢:Serverless / 王宏仁 / iThome電腦報周刊副總編輯

IT Home調查 2018 IT趨勢-值得關注的技術:Web Assembly , Kubernets , 金融 Open API, Chatbot NLP

(抱歉位置太爛拍得很爛…XD)

20180329_095430

- NETFLIX 前技術長提到IT架構的變革:虛擬化 -> 雲端 -> 容器 –> Serverless無伺服器架構

用哪種?以房子做比喻:

- 自建機房:買套房/房子
- 虛擬化:自家房子+隔間
- Cloud:租一層公寓(廚房.客廳.玄關.大門)+標準隔間
- Serverless無伺服器架構:租沙發

Serveless 實務案例介紹

- Skylink公司透過無人機+影像辨識針對工廠安全做巡檢,資料都是丟Serverless
- 可口可樂針讓販賣機做可用性分析,數據資料全丟AWD lambda,但之後量大的話還是會考慮丟Web App,因不會比較省成本。
- Abilisense公司透過穿戴裝置分析環境聲音+預警
- 亞旭電腦用Serverless結合IoT,讓BOM表Cost計算更直覺


設計、開發及部署跨平台的Serverless應用/上官林傑 -台灣微軟技術傳教士

Serverless 重點:伺服器抽象化、事件驅動立即延展、錙銖必較

常見的Serveless架構情境

- 即時串流服務
- IoT senser data
- 週期性工作 每15分鐘清除無效資料
- 程式後端服務 使用頻率無法估計
- 對談機器人 使用頻率無法估計

Azure Stack介紹:http://technews.tw/2017/08/30/microsoft-azure-public-cloud-is-on-the-ground-with-the-help-from-local-telecomm/

Serverless 建議

- 專注做一件事
- 應該冪等 Idempotent
- 盡快結束

玩玩Azure Function臉部辨識:https://www.tryfunctions.com/ng-min/try?trial=true


使用 Serverless 進行網站監控/ 104 呂昭寬 資深架構師

學習成本

- 取代管理成本
- 黑箱和地雷
- 限制:最多3分鐘不然會timeout , cpu memory storage , 程式語言的問題 (java要先開jvm之類的,不太適合)

Faas的強項

目標選擇

  • 可靠性很高,透過internet運行
  • 適合中低負載
  • 適合排程運行

例如可以用Aws lambda發出請求給網站,網站回200 404 timeout,送給Cloudwatch整理成報表

也可以進一步檢查Domain name解析時間,等候請求時間,tcptls hand shake連線等等

20180329_113420


Spacer - 我為什麼自製了一個 Serverless 平台 / 柏傑(Poga)  - APlace DesignConsultant

本場次講者整合工具,自做了一個Serverless platform,可以去Github看看 https://github.com/poga/spacer

本次也看到 Lua 這個嵌入式程式語言,語法看起來蠻簡潔的:https://zh.wikipedia.org/wiki/Lua


OpenFaaS - 快速打造你的 Serverless 平台 / 王偉任(Weithenn) - 東森購物架構師

要評估容器技術,現在有很多可以直接線上玩了

實作容器部署
Play with Docker:https://labs.play-with-docker.com/
Play with Kubernetes:https://labs.play-with-k8s.com/


Ops as Code using Serverless / 黃冠元(Rick) / 91APP技術經理

整個演講的內容,講者已經整理到他blog

https://rickhw.github.io/2018/03/29/About/2018-Serverless-All-Star/

20180329_140133


Angular+Firebase:快速建立最小可行性產品 / 林承翰(JB) - 華立企業權任課長

講者是一位PM,目前會利用兩者技術來快速做一些prototype確認客戶需求

https://github.com/angular/angularfire2

推薦保哥之前也講過相關的題目:https://www.slideshare.net/WillHuangTW/jsdctw-2016-angular-2-firebase-serverless-67522007


秒發百萬推播 / 范建銘 - 工程師

講者是個很古意的工程師 XD

以往自建機房,因設備問題,推播App訊息常常因為效能問題導致無法在對的時間發送,並且常常會讓資料庫掛掉。評估過GCP和AWS的Serverless技術,只有AWS承諾能達到秒即百萬推播的服務,Serverless上手容易,經過1.2個月的技術評估就能將此需求上到雲方案,且非常的節省成本,解決問題,但實務上還是踩到一些雷,例如還是得分幾批發送、及有時會發生推播兩次的情形發生。

2018年4月4日 星期三

東西拿了就走 - Amazon Go 無人商店初體驗

Amazon Go 介紹

今年有幸至西雅圖參與 Miscrosoft MVP Global Summit , 還是撥空安排了一些行程 , 身為一個攻城獅怎麼不能來體驗 目前全球僅此一家的 Amazon Go 無人商店呢 ~

要進入 Amazon Go 之前必須要先下載App和註冊信用卡,進去以後透過App的QR Code 就能進去了,跟高鐵一樣~

20180308_121026

Just Walk Out Shpping

20180308_121041

入口處的機器,類似高鐵,只要將註冊完的App透過QR Code掃描即可進入

20180308_121139

身為一個攻城獅,大家只看個超市內的商品,而我們是抬頭看看這些攝影機的擺設 XD

20180308_121410

Amazon Go 裡面的商品就跟一般的美國商品沒兩樣

20180308_121935

買了一個Amazon的巧克力,非常適合當伴手禮

20180308_121739

店家外面有提供休息站,意外發現一名熱血工程師就在這邊打Code

20180308_122256

旁邊就是 Amazon 西雅圖總部 - 巨型植物園

20180308_122618

心得

目前仍在營運測試階段,故還是會有店員在現場,但主要負責是門口的教育訓練和補貨

使用體驗起來真的還不錯,想像一下進到 7-11 亂拿東西直接出門口的感覺

整個過程是很順的,出了門口閘道馬上收到信用卡刷卡通知

當下有跟朋友想了幾個測試情境,譬如交換外套、遮臉、把商品快速來回擺放…

但礙於實在太丟臉了,所以沒這樣做 XD

無人商店普及後,我想會大大改變我們的消費行為,期待那一天的到來 :)

技術

親身體驗後,回台馬上去研究了一下核心技術,以下有幾篇文章可以參考看看

https://buzzorange.com/techorange/2017/03/10/how-to-build-shop-like-amazon-go/

http://benevo.pixnet.net/blog/post/64772716-amazon-go-%E4%B8%89%E5%A4%A7%E6%A0%B8%E5%BF%83%E6%8A%80%E8%A1%93

2018年3月29日 星期四

使用 LinqPad 快速產生 Dapper 所需要的 SQL 語法 - Class、Insert、Update

前言

工作上目前已經很習慣用 Dapper 這種輕型的 ORM 來處理有關DAL層的應用,但相較於 Entity Freamwork,在處理新增/更新時就比較沒那麼方便,主要差異在Entity Freamwork 可以直接用物件操作的方式來做資料庫異動,而Dapper就必須寫SQL Commend,雖然有一些Open Source Extentions 已經封裝這些邏輯,譬如:SimpleCRUD﹉等,但實際使用常常得依規範設定一些屬性,有時發生錯誤時也不是那麼的直覺,故目前我還是會以SQL Commend為主。但產生Commend是一件麻煩事,如果搭配 Linqpad 寫一個Script 可以依需求快速產生所需要的commend,彈性是很大的,此篇文章介紹我在實務上我常用Scripts,來快速產生相關 SQL Commend

如何設定LinqPad

20180311_015834

Step 1 : 這邊可以直接瀏覽資料庫的Schema
Step 2 : 這邊使用C# Program 來撰寫我們要產生Script的程式
Step 3 : 選擇資料庫的連線字串

接著以下是我常用的Helper,只要貼到內容裡面即可產生


 

void Main()

{

 this.Connection

 .DumpClass(@"

SELECT * FROM Table

 ","ViewModelName")

 .Dump();

}

// Define other methods and classes here

public static class LINQPadExtensions

{

 private static readonly Dictionary TypeAliases = new Dictionary {

 { typeof(int), "int" },

 { typeof(short), "short" },

 { typeof(byte), "byte" },

 { typeof(byte[]), "byte[]" },

 { typeof(long), "long" },

 { typeof(double), "double" },

 { typeof(decimal), "decimal" },

 { typeof(float), "float" },

 { typeof(bool), "bool" },

 { typeof(string), "string" }

 };

 private static readonly HashSet NullableTypes = new HashSet {

 typeof(int),

 typeof(short),

 typeof(long),

 typeof(double),

 typeof(decimal),

 typeof(float),

 typeof(bool),

 typeof(DateTime)

 };

 public static string DumpClass(this IDbConnection connection, string sql,string Name)

 {

 if(connection.State != ConnectionState.Open)

 connection.Open();

 var cmd = connection.CreateCommand();

 cmd.CommandText = sql;

 var reader = cmd.ExecuteReader();

 var builder = new StringBuilder();

 do

 {

 if(reader.FieldCount <= 1) continue;

 builder.AppendLine("public class " + Name);

 builder.AppendLine("{");

 var schema = reader.GetSchemaTable();

 foreach (DataRow row in schema.Rows)

 {

 var type = (Type)row["DataType"];

 var name = TypeAliases.ContainsKey(type) ? TypeAliases[type] : type.Name;

 var isNullable = (bool)row["AllowDBNull"] && NullableTypes.Contains(type);

 var collumnName = (string)row["ColumnName"];

 builder.AppendLine(string.Format("\tpublic {0}{1} {2} {{ get; set; }}", name, isNullable ? "?" : string.Empty, collumnName));

 }

 builder.AppendLine("}");

 builder.AppendLine(); 

 } while(reader.NextResult());

 return builder.ToString();

 }

}


產生 Insert 語法



void Main()
{
 // SQL Command
 var sqlCommand = @"SELECT top 1 * FROM dbo.Table WITH (NOLOCK);";
 
 this.Connection.GenerateInsertCommand(sqlCommand.ToString(), "Table").Dump();
 
}
 
public static class LINQPadExtensions
{
 public static string GenerateInsertCommand(this IDbConnection connection, string sql, string tableName = "TableName")
 {
 if (connection.State != ConnectionState.Open)
 {
 connection.Open();
 }
 
 var cmd = connection.CreateCommand();
 cmd.CommandText = sql;
 var reader = cmd.ExecuteReader();
 
 var builder = new StringBuilder();
 do
 {
 if (reader.FieldCount <= 1)
 {
 continue;
 }
 
 builder.AppendFormat("INSERT INTO [dbo].[{0}]{1}", tableName, Environment.NewLine);
 builder.AppendLine("(");
 
 var schema = reader.GetSchemaTable();
 var columnNames = new List();
 
 foreach (DataRow row in schema.Rows)
 {
 var columnName = (string)row["ColumnName"];
 columnNames.Add(columnName);
 }
 
 foreach (var columnName in columnNames)
 {
 builder.AppendFormat(" [{0}]{1}{2}",
 columnName,
 columnNames.IndexOf(columnName).Equals(columnNames.Count - 1) ? "" : ",",
 Environment.NewLine);
 }
 
 builder.AppendLine(")");
 builder.AppendLine("VALUES");
 builder.AppendLine("(");
 
 foreach (var columnName in columnNames)
 {
 builder.AppendFormat(" @{0}{1}{2}",
 columnName,
 columnNames.IndexOf(columnName).Equals(columnNames.Count - 1) ? "" : ",",
 Environment.NewLine);
 }
 
 builder.AppendLine(");");
 builder.AppendLine();
 }
 while (reader.NextResult());
 
 return builder.ToString();
 }
}


產生 Update 語法


void Main()
{
 // SQL Command
 var tableName = "TableName";
 var sqlCommand = @"SELECT top 1 * FROM [dbo].["+tableName+"]";
 
 this.Connection.GenerateInsertCommand(sqlCommand.ToString(), tableName).Dump();
 
}
 
public static class LINQPadExtensions
{
 public static string GenerateInsertCommand(this IDbConnection connection, string sql, string tableName = "TableName")
 {
 if (connection.State != ConnectionState.Open)
 {
 connection.Open();
 }
 
 var cmd = connection.CreateCommand();
 cmd.CommandText = sql;
 var reader = cmd.ExecuteReader();
 
 var builder = new StringBuilder();
 do
 {
 if (reader.FieldCount <= 1)
 {
 continue;
 }
 
 builder.AppendFormat("UPDATE [dbo].[{0}] SET {1}", tableName, Environment.NewLine);
 // builder.AppendLine("(");
 
 var schema = reader.GetSchemaTable();
 var columnNames = new List();
 
 foreach (DataRow row in schema.Rows)
 {
 var columnName = (string)row["ColumnName"];
 columnNames.Add(columnName);
 }
 
 foreach (var columnName in columnNames)
 {
 builder.AppendFormat(" [{0}] = @{0}{1}{2}",
 columnName,
 columnNames.IndexOf(columnName).Equals(columnNames.Count - 1) ? "" : ",",
 Environment.NewLine);
 }
 
 builder.AppendLine("WHERE ID = @ID");
 }
 while (reader.NextResult());
 
 return builder.ToString();
 }
}

2016年11月19日 星期六

[Angular2] 在專案加入多國語系

前言

在專案啟動時,我習慣直接將多國語系考慮進去,不然到時老闆一句話要Support時又要將所有程式改動挺麻煩的,在Angular2有一個整合i18n的模組叫做ng2-translate ,本篇文章就來說明如何將它加入專案中。

如何建立範本請參考 [Angular2] 建立專案範本

 

NPM安裝

$ npm install ng2-translate –save
or
$ yarn add ng2-translate

 

模組Import

Angular2 變成模組化開發後載入第三方函示庫不外乎就是 NPM安裝=>找你的模組匯入,此範例我們打開app.module.ts

螢幕快照 2016-11-20 上午10.30.29

這樣就會載入transModule,此設定翻譯檔預設會抓網站底下的i18n目錄,如果你要自訂翻譯檔的路徑可以改由以下設定:

@NgModule({
    imports: [
        BrowserModule,
        HttpModule,
        TranslateModule.forRoot({
            provide: TranslateLoader,
            useFactory: (http: Http) => new TranslateStaticLoader(http, '/assets/i18n', '.json'),
            deps: [Http] 
        })
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

 

語言設定

接著打開根元件app.conponent.ts,使用TranslateService並設定語言

螢幕快照 2016-11-20 上午10.52.16

 

定義翻譯檔

開發階段src為網站目錄,我們在src資料夾底下增加i18,並增加en.json & zh.json

en.json

{
    "HelloTrans": "Learing ng2-translate!"
}

zh.json

{
    "HelloTrans": "實作多國語系!"
}

 

使用翻譯檔

Html 要抓取翻譯檔定義需改由以下寫法


<div>
    {{ 'HelloTrans' | translate }}
</div>

而在.ts要抓取翻譯檔定義則需要使用Service

translate.get('HelloTrans').subscribe((val: string) => {
     console.log('HelloTrans',val);
});

 

切換語系

而切換語系也很簡單,我們在html加入兩個按鈕

<button class="btn btn-primary" (click)="changeLang('en')">切換語系至English</button>
<button class="btn btn-primary" (click)="changeLang('zh')">切換語系至中文</button>

在app.component.ts增加changeLang這個method

changLang(langKey){
     this.translate.use(langKey);
}

這樣就可以完成語系切換,而當使用者重新整理網頁時要怎麼維持當前語系呢? 通常我會使用localStorage來處理,譬如在app.conponent.ts底下改成如下:

螢幕快照 2016-11-20 上午11.07.24

 

後記

使用多國語系一點也不複雜,而且因為是使用Angular2開發,如果您有在寫ionic2 要在App做多國語系也是差不多的步驟~

而.json檔通常是給專業的翻譯,這部分可以找一些線上工具,將excel樣板提供給翻譯人員完成,之後再將excel檔轉成json檔,後續也較好維護。

至於i18n的語系代碼可參考 http://www.science.co.il/Language/Codes.php

--

本次範例程式 : https://github.com/kyleap/angular-learn-sample

2016年11月10日 星期四

[Angular2] 在angular-cli專案加入第三方套件-以jQuery及Bootstrap為例

前言

接觸angular後其實真的很少寫jQuery,但很多時候拿到的html版可能是UI設計師所提供的,或者是花錢買的樣板,所以免不了要用jQuery寫入一些效果,本篇就簡單介紹一些如何在angular-cli專案加入第三方的.js .css.
如何建立範本請參考 [Angular2] 建立專案範本

webpack

angular2是個模組化的開發方式,透過angular-cli所建置的專案已改由system.js改由webpack,以往要在angular2專案加入webpack,你必需要去了解webpack的建置環境,這對於一個全端工程師來說是個很焦慮的事XD,因為webpack要懂得的東西還真的不少,好在angular-cli已幫我們整合好,只要懂得用他的指令即可,而angular-cli相關webpack設定檔都至於node_modules底下,而webpack本身還有許多額外的套件,如果要增加的話不建議直接改node_modules這些設定檔,可在專案底下加入會比較彈性一點。
螢幕快照 2016-11-11 下午1.08.32
angular.cli.json
webpack會將我們相依的程式及模組打包成一隻.js減少request,而以下就介紹如何在專案下加入jQuery及bootstrap
先用yarn將jQuery及bootstrap安裝回來
# yarm是完全相依npm的套件管理工具,執行上比npm快非常多,可參考此篇文章
$ yarn add jQuery bootstrap
package.json
螢幕快照 2016-11-11 下午1.20.48
在angular.cli.json 加入路徑
"styles": [
           "styles.css",
           "../node_modules/bootstrap/dist/css/bootstrap.min.css"
       ],
       "scripts": [
           "../node_modules/jquery/dist/jquery.min.js"
],
接著我們app.component.html加入一個bootstrap的Button (強烈建議編輯器要安裝snippet套件快速開發)
螢幕快照 2016-11-11 下午1.31.47
ng serve 啟動本機伺服器 可以看到已套用bootstrap
螢幕快照 2016-11-11 下午1.34.46
接著在app.component.ts加入jQuery試試
螢幕快照 2016-11-11 下午1.36.38
這時你會發現 $ 字號有毛毛蟲 這是因為Typescript是強行別的開發方式,檢查會變得較為嚴謹,任何開發尚未定義的變數都會在編譯時期就出錯。
而要讓Typescript看得懂 $ 字號為jQuery其實只要宣告一下就好了:
declare var $:any;

TypeScript With jQuery

而宣告成any還不夠帥,且每支檔案都要宣告一次還挺麻煩的,我們可以將此宣告移到一個全域的地方,
並且載入Typescript的jQuery設定檔定義檔,讓開發起來更順手
安裝jQuery Typescript定義檔:
$ yarn add @types/jquery
找到src/tsconfig.js,有關Typescript的設定都會在這檔案,加入types
"types": [
         "jquery"
     ]
接著回到app.componet.ts,會看到有關jQuery語法都開始會有智慧提示功能 (VS Code Rock!!)
螢幕快照 2016-11-11 下午1.50.22
在執行一次ng serve,即可看到jQuery正常執行
螢幕快照 2016-11-11 下午1.52.03
原則上Typescript用第三方函示庫就要有相對應的.d.ts定義檔,如果該函示庫如果沒有定義檔也可以自行製作一個
可參考保哥的教學影片 https://www.youtube.com/watch?v=_9fUQus6EqQ
或者是可以考慮在src/typings.d.ts進行全域的宣告也可
--
本次範例程式 : https://github.com/kyleap/angular-learn-sample

2016年10月15日 星期六

[Angular2] 在每個Request加入自訂的Header資訊

前言

開發架構都偏向後端是個REST API,而要做到身分驗證必須要走OAuth協定,而我們系統採用的是 Bearer Token ,Client 像 Server 端取得Access Token後,只要在Header加入Key 為 Authorization的格式,就能判斷該Request的登入身分,而這個 Header的Value 會長這樣

Bearer XXXXXXXX
而在Angular2如何在每次像API發送Request的時候怎麼夾帶這個資訊呢?
範本安裝請參考 : http://kyleap.blogspot.tw/2016/10/angular2.html
== 前端版號很重要 ==

angular-cli: 1.0.0-beta.17
node: 6.6.0
angular : 2.0.0

== 前端版號很重要 ==

1. 於app目錄加入app.request.ts,並加入以下程式

 

螢幕快照 2016-10-15 下午5.14.07

自訂的AppRequestOptions繼承(extends)BaseRequestOptions Class,並執行底層Class的建構(super()),而如有登入過通常我會將OAuth所回傳的Token資訊存在localStorage,故判斷如果有資料的話則在Headers加入Authorization

2. 於app.module.ts 注入app.reqequest

螢幕快照 2016-10-15 下午5.33.00

螢幕快照 2016-10-15 下午5.37.07

http模組加入RequestOptions及匯入剛剛的app.request.ts及於App Module注入即可

接著打開瀏覽器開發工具,就可以看到http發送Request後就可以看到Header多了Authorization

螢幕快照 2016-10-15 下午5.44.54

後記

這個方法可以很容易的帶入我們要的Header資訊,而還有另一個方式是自訂一個Http Provider,有機會再寫另一篇分享

本次範例程式 : https://github.com/kyleap/angular-learn-sample

--

References

https://angular.io/docs/ts/latest/api/http/index/BaseRequestOptions-class.html

 

 

 
 
 

2016年9月28日 星期三

[Angular2] 建立專案範本

前言

身為一個全端工程師,除了網站前後端外,在專案上開始也有開發App的需求,在過去我們團隊使用Angular來撰寫前端程式,後端採用ASP.NET Web API,而App我們使用Cordova搭配ionic 。但專案進入維護期,有新人也加入了,但因為Angular學習曲線有點太高,導致會不太好上手,且專案一大,因為是使用JavaScript開發,如果對於JavaScript特性不太熟悉,很容易掉入地獄裡面。在今年評估Angular2後,決定狠下心從將Angular1重構成Angular2專案,因為是搭配TypeScript來開發,搭配編輯器的功能,讓有些錯誤可以在編譯時期,且編輯器自動完成功能讓開發起來更加順手,對於TypeScript有種相間恨晚的感覺,應該在Angular1時間就使用TypeScript來撰寫會比較順手。

Angular2學習曲線我認為也不低,複雜在於"開發環境",他將自己定位成平台,所以整合很多的open source技術進來,但就一個團隊新人來講,開發環境並不是首要去了解的,很多事情都定義成腳本,只要會使用就可以。就程式撰寫上,Angular2的學習曲線我覺得大大的降低,且因為官方就訂了很多程式開發標準.建議,讓使用Agnular2開發的人都有一致的開發風格,這也是後來在github看別人專案也能很快看懂的原因。

目前(2016年)也已經進入正式版,這篇文章算是一個開始,我陸續想將開發上所撰寫的功能及採到的地雷,整理成一篇一篇的小筆記,而不免俗的來Hello Word一下,讓之後demo的Sample Code都以此篇的專案範本來撰寫。

建立Angular2專案範本

使用前請安裝Node.js 會一併安裝NPM

可以用指令確認版本

螢幕快照 2016-10-08 下午9.46.40

透過NPM安裝 Angular-cli

npm install –g angular-cli

ng –v 確認版本

螢幕快照 2016-10-08 下午9.48.16

ng new mydemo 建立專案
cd mydemo 進入資料夾
ng serve 啟動本機localserver

用瀏覽器開啟http://localhost:4200/

如果有出現app work!畫面代表成功。

--

本篇利用Angular-cli很簡單的建立範本讓之後的文章做參考,

建議可以參考 Angular2官網手把手接學  照步驟做完應該就會開發了XD

也可以參考保哥的文章,整理很多Angular2觀念及延伸學習資源

文章索引連結(陸續新增)

Angular 2

[Angular2] 在每個Request加入自訂的Header資訊

[Angular2] 在angular-cli專案加入第三方套件-以jQuery.Bootstrap為例

[Angular2] 在專案加入多國語系

 

Ionic 2