﻿# 如何在 Angular CLI 建立 proxy.config.json 轉發呼叫遠端 RESTful APIs

最近開辦了許多 Angular 2 訓練課程，許多學員都有提到一個問題，就是如何讓我們現有的 ASP.NET MVC 5 網站跟 Angular 2 整合在一起。這個問題有個很簡單的回答：**不要在開發時期整在一起，部署的時候放在一起就好**！但是 Angular 2 網站在開發的過程中要怎樣才能成功呼叫我們用 ASP.NET MVC 或 ASP.NET Web API 寫好的 RESTful API 呢？本篇文章將介紹一個鮮為人知的「內建功能」，可以讓你在開發時期就可以很方便的呼叫任意遠端任意 HTTP API 介面。

### 新版 Angular 作法

新版的 Angular CLI 可以直接在 `angular.json` 定義 `proxy.conf.json` 的路徑，不用再調整 `package.json` 檔案的 `scripts` 設定，詳情請直接參考 [代理到後端伺服器](https://angular.tw/guide/build#proxying-to-a-backend-server) 官網文件。

以下是設定步驟：

1.  建立 `src/proxy.conf.json` 代理伺服器設定檔
    
    ```json
    {
      "/api": {
        "target": "http://localhost:8080",
        "secure": false,
        "changeOrigin": true
      }
    }
    ```
    
2.  在 `angular.json` 中為 `serve` 目標新增 `proxyConfig` 選項
    
    ```json
    …
    "architect": {
      "serve": {
        "builder": "@angular-devkit/build-angular:dev-server",
        "options": {
          "proxyConfig": "src/proxy.conf.json"
        },
    …
    ```
    
3.  執行 `ng serve` 啟動開發伺服器，即可自動將 `/api/*` 自動轉發到 `http: //localhost:8080/api/*` 了！
    

### 舊版 Angular 作法

今天我們會以[臺北市政府資料開放平台](https://data.taipei/)裡面的【[臺北市行人專用清潔箱](https://data.taipei/dataset/detail?id=a835f3ba-7f50-4b0d-91a6-9df128632d1c)】作為我們本篇文章的設定範例，以下是「中正區行人專用清潔箱」的 API 網址，等等用的到！

> http://data.taipei/opendata/datalist/apiAccess?scope=resourceAquire&rid=0b544701-fb47-4fa9-90f1-15b1987da0f5

![image](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/186cc67a1a3907344db5-image_3024.png)

首先，各位可以先參考 [Angular 2 開發實戰：新手入門篇 實作環境說明](https://gist.github.com/doggy8088/e0cb494aa28d40a0fb651559a7933dd8) 這份文件設立 Angular 2 開發環境。

然後透過以下命令建立好一個完整的 Angular 2 開發環境：

```bash
ng new demo1 --skip-tests
```

然後用 Visual Studio Code 開啟 demo1 專案資料夾

```bash
code .
```

開啟 `app.component.ts` 檔案 (`AppComponent`) 並注入 Http 服務元件，並嘗試取得「中正區行人專用清潔箱」的 API 內容 ( JSON 格式 )

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/0b2423c2663e1a156fdd-image_3025.png)

> https://gist.github.com/doggy8088/b0727809034215bcd3b781320cece455

此時我們設定一下 `app.component.html` 直接發出 HTTP GET 要求的結果，並用 `jsonPipe` 元件格式化

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/e978cc4807507e60e0c5-image_3026.png)

是的，沒錯，Angular 2 就只要簡單幾段程式，就可以將 API 資料取回並顯示在頁面上！

這時我們在命令提示字元下輸入 **npm start** 啟動 Angular CLI 內建的網站開發伺服器，並聯到 [http://localhost:4200/](http://localhost:4200/ "http://localhost:4200/") 測試網址，方便我們直接瀏覽執行結果，不過這時你卻會看到 **<span style="color: #0000ff;">null</span>** 顯示在畫面上而已。

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/9d093965af853450081b-image_3027.png)

我們按下 F12 的 Console 頁籤查看錯誤訊息，你會看到這個 HTTP GET 要求失敗了，原因是遠端的 API 並沒有實作 CORS 協定，因此 Angular 2 並無法從 [http://localhost:4200](http://localhost:4200 "http://localhost:4200/") 發送跨網域要求到 [http://data.taipei](https://data.taipei/dataset/detail?id=0b544701-fb47-4fa9-90f1-15b1987da0f5 "http://data.taipei/opendata/datalist/apiAccess?scope=resourceAquire&rid=0b544701-fb47-4fa9-90f1-15b1987da0f5") 這個網域！

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/c0bc0852a01db5173770-image_3028.png)

以前遇到這個問題，我都會暫時安裝 [Allow-Control-Allow-Origin: \*](https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi) 這個 Chrome 擴充套件來嘗試跳過瀏覽器的 CORS 安全檢查，不過這真的不是一個好方法，因為當你啟用之後會降低你的瀏覽器安全性，有時候經常會忘記關閉，導致你的瀏覽器將處與危險之中。

要解決這個問題，其實非常簡單，請參考以下步驟進行設定，我們現在就將 [http://data.taipei](https://data.taipei/dataset/detail?id=0b544701-fb47-4fa9-90f1-15b1987da0f5 "http://data.taipei/opendata/datalist/apiAccess?scope=resourceAquire&rid=0b544701-fb47-4fa9-90f1-15b1987da0f5") 這個網站的 /opendata 這個 API 路徑完整移植到我們的 Angular CLI 開發伺服器中！

1.  請在你的專案根目錄下新增一個 `proxy.conf.json` 設定檔，設定檔內容如下：
    
    ```json
    {
      "/opendata": {
        "target": "http://data.taipei",
        "secure": false,
        "changeOrigin": true
      }
    }
    ```
    
    **請注意：**
    
    1.  這裡的 `target` 是我們的目標 API 的網址，不能加上路徑部分
    2.  這裡的 `/opendata` 是我們要鏡像的網址 Prefix，所有連到 **http://localhost:4200/opendata/aaa** 網址，都會自動轉發到 **http://data.taipei/opendata/aaa**，以此類推！
2.  接著開啟 `package.json` 修改 `"script"` 區段中的 `"start"` 命令，加上 `--proxy-config proxy.conf.json` 參數，如下圖示：
    
    ![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/14cbf3c207dd0f39d32d-image_3029.png)
    
3.  最後修改 `app.component.ts` 檔案，將 url 的網址網域部分都刪除 ( 將 **http://data.taipei** 刪除，僅保留路徑部分 )
    
    ![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/68ae1a831eeb61cf0ff4-image_3030.png)
    
4.  停止先前執行的 `npm start` 並重新啟動即可
    

就這樣簡單設定，你現在的開發伺服器已經可以直接向本機開發伺服器網站發送 API 要求 (如下圖)，我們的 Angular CLI 開發伺服器現在會自動轉發所有 `/opendata/*` 要求到 `http://data.taipei/opendata/*` 網址，是不是非常便利呢！ 😃

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/18bfb416fc93171463c6-image_3031.png)

### 相關連結

-   [代理到後端伺服器](https://angular.tw/guide/build#proxying-to-a-backend-server)
-   [angular/angular-cli: CLI tool for Angular](https://github.com/angular/angular-cli#proxy-to-backend) -> Proxy To Backend
-   [webpack dev server](https://webpack.js.org/configuration/dev-server/)
-   [Some https proxy urls failed · Issue #4322 · angular/angular-cli](https://github.com/angular/angular-cli/issues/4322#issuecomment-276765314)
-   [chimurai/http-proxy-middleware: The one-liner node.js http-proxy middleware for connect, express and browser-sync](https://github.com/chimurai/http-proxy-middleware#options)
