iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 29
0
Modern Web

用Angular打造完整後台系列 第 29

day29 Protocol Buffers 與 gRPC Web (一)

簡述

隨著微服務的趨勢,一個系統裡是有多個服務組成,
而且每個服務之間都要互相通訊,所以現在開始有一陣風吹向了gRPC

gRPC最麻吉的資料格式是Protocol Buffers
以往前後端溝通資料最大宗是Json格式,
但如果每個微服務都要用Json相互傳接值,
就要寫一大~堆的code~
然後就有些人崩潰了。

至少我遇到的後端崩潰了,
所以現在因為後端用 gRPC
我認真花了五天的時間搞懂跟串接。

Protocol Buffers

可能有人會問,
不是在各自的微服務中用gRPC跟Protocol就好,
為什麼跟前端通訊也要用?
其實呢,Protocol Buffers是一種資料格式

照以往流程中,API文件會定義Json格式,
然後前後端各自寫自己語言的model去對應。

但Protocol Buffers格式,
可以自動生成符合你用的程式語言的檔案,
也就是說前後端可以把Protocol Buffers自動轉成自己要的格式,
然後雙方都不用再寫model了。
(其實我還是會寫對應的model/images/emoticon/emoticon16.gif)

結論是等於是寫一次Protocol Buffers,各種語言的model都可以自動生成。
所以網上很多文章說Protocol Buffers本身是結構定義檔。

syntax = "proto3";

package pb;

import "base.proto";

message Customer {
    int64 id = 1;
    string name = 2;
    string account = 3;
    string password = 4;
    int32 status = 5;
    int64 level_id = 6;
    string level_name = 7;
    int64 inserted = 8;
    int64 insert_by = 9;
    int64 updated = 10;
    int64 update_by = 11;
}

現在只要看Protocol Buffers裡的物件,就知道參數跟型態有哪些了。

為什麼Protocol Buffers能自動生成各語言的model呢?
因為有出protoc編譯器可以轉成各語言的model。

以上述例子,要把這個 proto檔 轉給js使用,
於是我們用protoc把上面那隻service轉成js跟ts檔。
轉完的檔案會有customer_pb.d.tscustomer_pb.js

所以開發時只要寫出了一份Protocol後,前後端就可以各自把這份轉成自己的語言。


protoc使用說明:

操作於 Windows10 64bit
後端 Golang
前端 Angular

  1. 連結至 https://github.com/protocolbuffers/protobuf/releases
  2. 點擊 protoc-3.10.0-win64.zip 下載
  3. 解壓縮 protoc-3.10.0-win64.zip 會得到兩個資料夾及一個檔案
    bin/ include/ readme.txt
  4. 以下兩種操作選一個用
    • a. 開啟 PowerShell cd 至 bin 底下
    • b. 將 bin 加入 PATH 並重載環境變數 (登出, 重新開機...)
  5. 利用 protoc 產生出 protobuf grpc 需要用到的檔案
  • 建立一個資料夾放後產出的 go 檔

  • 格式 : protoc --go_out=plugins=grpc:${要輸出的資料夾} -I ${protofile 定義的路徑} filename

  • 實例 : protoc --go_out=plugins=grpc:../pb/golang -I C:/Protofiles *.proto

  • 建立一個資料夾放產出的 js ts 檔

  • 格式 : protoc --js_out=import_style=commonjs,binary:${要輸出的資料夾}
    --grpc-web_out=import_style=typescript,mode=grpcweb:${要輸出的資料夾} \
    -I ${protofile 定義的路徑} filename

  • 實際 : protoc --js_out=import_style=commonjs,binary:../pb/ts
    --grpc-web_out=import_style=typescript,mode=grpcweb:../pb/ts
    -I C:/Protofiles *.proto

  1. 移動 ../pb/go 的檔案至後端工作目錄內並實作 Service 物件
  2. 移動 ../pb/ts 的檔案至前端工作目錄內建立連線即可使用

上述流程如果看不太懂,別擔心我也是!
前端碰這些東西總是很難理解,請各位前端要跟後端打好關係,
然後請後端協助。^_^


gRPC

grpc是一種通訊協定。

以往我們比較常聽到的協定如:HttpRequest、WebSocket。

不管哪種協定都是用來與後端伺服器通訊。

為了讓大家好理解,以下舉個例子:

HttpClient

這是Angular包好的HTTP協定。

//HttpRequest
export class WebService {
  headers: HttpHeaders;

  constructor(private http: HttpClient) {}

  setHeaders(token: string) {
    this.headers = new HttpHeaders().set("Authentication", token);
  }

  getF<T>(url: string): Observable<T[]> {
    return this.http.get<T[]>(url, { headers: this.headers }).pipe(
      tap(res => this.logger.print("response", res)),
      catchError(this.handleError)
    );
  }

  ...
}

--

WebSocket

以及下面例子WebSocket協定 new WebSocket();

//WebSocket
export class WebService {
    ...
    private create(): Subject<MessageEvent> {
        const ws = new WebSocket(this.url);
        const observable = Observable.create(
        (obs: Observer<MessageEvent>) => {
            ws.onmessage = obs.next.bind(obs);
            ws.onerror = obs.error.bind(obs);
            ws.onclose = obs.complete.bind(obs);
            return ws.close.bind(ws);
        });
        const observer = {
            next: (data: Object) => {
                if (ws.readyState === WebSocket.OPEN) {
                    ws.send(JSON.stringify(data));
                }
            }
        };
    return Subject.create(observer, observable).share();
  }
}

--

gRPC Web

那我們採用gRPC協定,也要事先做一個連線處理的service,
並且這個service還要能給js使用。

所以我們用proto來寫個service,之後讓它各自轉成前後端語言。

//store.proto
syntax="proto3";

package pb;

import "base.proto";
import "admin.proto";
import "customer.proto";
import "product.proto";
import "order.proto";

service Store {
  ...
  // customer 修讀寫
  rpc FindCustomer(CustomerF) returns (CustomerFResult) {}
  rpc InsertCustomer(Customer) returns (DbMessage) {}
  rpc UpdateCustomer(Customer) returns (DbMessage) {}
  ...
}

然後要把這個 proto檔 轉給js使用,
於是我們用 protoc 把上面那隻service轉成js跟ts檔。
轉完的檔案就會有store_pb.d.tsstore_pb.js
StoreServiceClientPb.ts

Protocol Buffers還有個好處是不用另外編寫API文件,
像上述把寫個service.proto檔,易讀性很高,
前後端可以直接維護這份proto檔就好。

之後寫連線的部分:

export class WebService {
  apiUrl = APIURL;
  store: StoreClient;

  constructor() {
    this.store = new StoreClient(this.apiUrl, {}, {});
  }

上一篇
day28 Firebase(二)應用
下一篇
day30 Protocol Buffers 與 gRPC Web (二)
系列文
用Angular打造完整後台30

尚未有邦友留言

立即登入留言