>[success] # gRPC
1. `rpc(Remote Produce Call)`是一個,在后臺微服務開發階段將每個模塊進行獨立,模塊和模塊之間要進行通信就需要去實現傳輸協議,`RPC`中可以使用`HTTP`作為通訊協議,通訊協議只是`RPC`中的一部分。**RPC中還有序列化、反序列化**等等。
2. [gRPC](http://www.grpc.io/)是一種基于 HTTP2 的現代[協議,它使用](https://hpbn.co/http2/)[協議緩沖區的強類型](https://developers.google.com/protocol-buffers/docs/overview)*二進制*數據格式跨多種語言,[gRPC-Web](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md)是一種尖端規范,支持從*現代*瀏覽器調用 gRPC 服務

3. **GRPC中序列化、反序列化**使用[Protocol Buffers](https://developers.google.cn/protocol-buffers/docs/proto3)是 google 開發的用于序列化數據的開源機制,通過創建一個帶有`.proto`擴展名的文件來定義我們要發送/接收的數據的消息結構,以js轉換為例來說`.proto`文件為使用的[`protobuf-javascript`](https://github.com/protocolbuffers/protobuf-javascript/releases)插件作為 轉換為 `js` 文件
4. 通信`GRPC HTTP/2`實現都支持四種方法類型: 一元、服務器端、客戶端和雙向流(unary, server-side, client-side, and bi-directional streaming)
* **Unary** 常見的客戶端發起請求,服務端應答模式
* **Client-side Streaming** 用戶以流的形式發起請求,源源不斷,服務端再返回一次響應
* **Server-side Streaming** 用戶發起一個請求,服務端以流的形式源源不斷地返回響應
* **Bidirectional Streaming** 服務端、客戶端以流的形式進行雙向交互
[# gRPC的概念-- 四種流詳細參考](https://juejin.cn/post/7048536076863930375#heading-9)
>[success] # 瀏覽器使用gRPC
* google-protobuf + grpc/grpc-web
* google-protobuf + @improbable-eng/grpc-web
>[info] ## grpc-web 方案
1. 使用 `grpc-web` 方案需要 **`proto`文件編譯成 `js `代碼,然后引入 `js `代碼,調用提供好的 `grpc `方法**
2. 需要先下載[`protoc協議編譯器安裝`](https://github.com/protocolbuffers/protobuf/releases/) ,是為了可以轉換`Protocol Buffers`,`Protocol Buffers`是谷歌的語言中立、平臺中立、可擴展的結構化數據序列化機制一種協議,使用特殊生成的源代碼輕松地使用多種語言在各種數據流中寫入和讀取結構化數據
3. 需要在下載`Protobuf` 轉換成對應的語言的轉換插件,以`grpc-web` 方案為例需要下載[`protoc-gen-grpc-web`](https://github.com/grpc/grpc-web/releases),如果你是`windows `電腦安裝上面兩個插件后,將`protoc-gen-grpc-web`(注意名字也要叫這個)放到`protoc`的`bin`目錄
~~~
.
|-- bin
| |-- protoc-gen-grpc-web.exe
| `-- protoc.exe
~~~
將配置增加到環境變量后,現在 可以執行(下面腳本意思將`greetHell.proto` 文件輸出一份`js`版本,一份`web` 版本輸出的格式為`js`)`js_out`此選項為請求和響應創建 JS 模型。(根據我們的原型文件,**輸入** 和 **輸出** 對象),`grpc-web_out`為瀏覽器創建 gRPC 客戶端以發送 gRPC 請求并接收響應
~~~
protoc -I=. ./greetHell.proto --js_out=import_style=commonjs:./ --plugin=protoc-gen-grpc=./protoc-gen-grpc-web.exe --grpc-web_out=import_style=commonjs,mode=grpcwebtext:./
~~~

* 如果你執行過程中提示`# "--js\_out: options: mode is required" error on code generation` 可以將`protoc 降級到 v3.20.1`([link](https://github.com/protocolbuffers/protobuf/releases/tag/v3.20.1))**版本對應的是**[`Protocol Buffers`](https://developers.google.cn/protocol-buffers/docs/proto3)**語法版本**
*****
4. 如果就想使用最新[`Protocol Buffers`](https://developers.google.cn/protocol-buffers/docs/proto3)語法,在新的提議中 建議 js 轉換使用單獨的插件,你可以下載[`protobuf-javascript`](https://github.com/protocolbuffers/protobuf-javascript/releases)作為js 單獨轉換文件的工具,在配合[`protoc-gen-grpc-web`](https://github.com/grpc/grpc-web/releases)轉換`web`版本代碼(`protoc-gen-grpc-web`僅作web 準換不再新版本`protoc `插件中同時可以轉換 `proto`文件為`js`)
*****
* 你是`window `很遺憾你會遇到 `libstdsc++-6.dll was not found` `libwinpthread-1.dll was not found`兩個報錯 這是因為[`protobuf-javascript`](https://github.com/protocolbuffers/protobuf-javascript/releases)目前`Windows.exe` 編譯程序還有問題,你的動手能力強可以[參考](https://github.com/protocolbuffers/protobuf-javascript/issues/142)解決方案,截至現在`3.21.2`還沒有修復,因此你可能仍然只能使用**protoc 降級到 v3.20.1** 版本和**protoc-gen-grpc-web** 進行配合
*****
* 你可以使用Windows 的 `wsl` 安裝一個`Linux`子應用,通過下載Linux 版本的[`protoc`](https://github.com/protocolbuffers/protobuf/releases/)、[`protoc-gen-grpc-web`](https://github.com/grpc/grpc-web/releases)、[`protobuf-javascript`](https://github.com/protocolbuffers/protobuf-javascript/releases)下載完成后,將文件中 `bin` 文件夾中文件移動到`user/bin` 中。例如`mv protoc /usr/bin/` 將三個插件 `bin` 執行文件都移動到`/usr/bin/`
~~~
protoc -I=. ./greet.proto --js_out=import_style=commonjs:. --grpc-web_out=import_style=commonjs,mode=grpcwebtext:.
~~~
5. 使用 `ts` 版本安裝,`protobuf-javascript` 只能轉換文件為`js`,如果想讓轉換的文件為`ts` 需要使用插件[
`ts-proto`](https://github.com/stephenh/ts-proto)
* 安裝 `npm install ts-proto`,具體使用參看文檔
~~~
protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_out=. ./simple.proto
~~~
>[danger] ##### protoc 指令含義
這里以[`protoc-gen-grpc-web`](https://github.com/grpc/grpc-web) 為例 官方給的指令案例
~~~
$ protoc -I=$DIR echo.proto \
--js_out=import_style=commonjs:$OUT_DIR \
--grpc-web_out=import_style=commonjs,mode=grpcwebtext:$OUT_DIR
~~~
* `-I`:input 作為指定的輸入轉譯`proto`文件
* `js_out`/`grpc-web_out`會分別使用[`protoc-gen-grpc-web`](https://github.com/grpc/grpc-web/releases)和[`protobuf-javascript`](https://github.com/protocolbuffers/protobuf-javascript/releases)插件將 `proto`文件轉換為`客戶端`和`消息`這兩個部分

* `import_style`轉換為 `js` 的代碼格式,先看`protoc-gen-grpc-web`支持轉換的類型有`closure`、`commonjs`、`commonjs+dts`、`typescript` 四種類型([Closure](https://developers.google.com/closure/library/)具體類型解釋參考),`protobuf-javascript`轉換格式只有`commonjs`
* `mode`,作為`protoc-gen-grpc-web`類型請求有兩種`mode=grpcwebtext`和`mode=grpcweb`,兩者分別對應**application/grpc-web-text(Base64編碼,文本格式) 和 application/grpc-web+proto(二進制格式),前者支持 Unary Calls 和 Server Streaming Calls,后者只支持 Unary Calls。**
* `:` 表示輸出生成文件地址
下面例子意思是將當前的文件下所有`.proto`轉移后放到 `src/proto`文件下
~~~
protoc *.proto --js_out=import_style=commonjs:../src/proto --grpc-web_out=import_style=commonjs,mode=grpcwebtext:../src/proto
~~~
>[danger] ##### 準備proto 文件
需要服務端提供的`proto` 文件當然也可以自己編寫`proto` 文件
~~~
syntax = "proto3"; // 指定使用proto3,如果不指定的話,編譯器會使用proto2去編譯
package greet; // 編譯后的包名
message HelloRequest { // 定義請求對象類型
string name = 1; // string 類型name 字段1為 該成員編碼時用1編號代替名字
}
message HelloReply { // 定義響應對象類型
string message = 1; // string 類型name 字段1為 該成員編碼時用1編號代替名字
}
service Greeter { // 定義服務接口
//定義一個方法,SayHello 請求參數HelloRequest類型響應是HelloReply類型
rpc SayHello (HelloRequest) returns (HelloReply){};
}
~~~
* 對`package `字段做一個說明,當將`proto`文件進行轉譯后,導出的包是`module.exports = proto.greet;` 和`package ` 字段定義一致

>[danger] ##### 使用
生成的兩個`*_web_pb.js` 和 `*_pb.js` 兩個文件。分別引入了
~~~
grpc.web = require('grpc-web');
// 和
var jspb = require('google-protobuf');
~~~
所以因此要引入對應兩個包`google-protobuf` 只要`npm i google-protobuf` 但`grpc-web` 卻給了兩個選擇`grpc/grpc-web` 和 `google-protobuf / @improbable-eng/grpc-web`
>[info] ## grpc/grpc-web vs google-protobuf / @improbable-eng/grpc-web

圖片來源:[Envoy and gRPC-Web: a fresh new alternative to REST](https://blog.envoyproxy.io/envoy-and-grpc-web-a-fresh-new-alternative-to-rest-6504ce7eb880)
`grpc-web` 并不是通過Http2 來實現的,這里要說明兩點
* `grpc`協議層是通過`HTTP2`作為通信協議,但是gRPC 不能使用瀏覽器中`HTTP2`,因為[它們沒有](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md)(并且可能不會)提供足夠的 API ,因為**gRPC-Web**,無法強制直接使用瀏覽器的 `HTTP/2`底層的`API`,即使有瀏覽器也不會讓`grpc-web`控制原始的 `HTTP/2`,因此`gRPC-Web` 只能從規范的角度出發,然后定義[差異](https://grpc.io/blog/state-of-grpc-web/),利用瀏覽器已有暴露的可控api去實現符合`grpc`定義規則。要明白瀏覽器是支持`HTTP2`發送請求,但已經高度封裝,`gRPC-Web`需要的是更細致化的`HTTP2 API`的暴露去完成一些自己的自定義開發,但顯然在瀏覽器這里行不通
* `grpc-web`其基本思想是讓瀏覽器發送普通的 `HTTP `請求可以是`1.1` 也可以是`2.x`(但是發送形式使用 `Fetch `或 `XHR`,并不是我們所理解`GRPC`) ,并在 `gRPC `服務器前設置一個小代理,將請求和響應轉換為瀏覽器可以使用的內容


谷歌有兩個團隊提供了`Grpc-web` 在瀏覽器的實現[官方 gRPC-Web](https://github.com/grpc/grpc-web)和[@improbable-eng/grpc-web](https://github.com/improbable-eng/grpc-web),之前說過 通信`GRPC`實現都支持四種方法類型: 一元、服務器端、客戶端和雙向流(`unary, server-side, client-side, and bi-directional streaming`),但在`gRPC-Web` 規范并沒有明確要求任何客戶端或雙向流支持
* 關于[兩個庫的對比 The state of gRPC in the browser | gRPC](https://grpc.io/blog/state-of-grpc-web/#f5)

* 但是`@immaybe-eng/grpc-web` 通過一個實驗性的 websocket 傳輸支持客戶端和雙向流
* 二者客戶端有不同的通信傳輸方式。 官方的 `gRPC-web` 只支持 `XMLHttpRequest`。 `@ immaybe-eng/grpc-web` 另外還支持 `Fetch`
* 二者推薦使用的中間層也不同中間層(代理客戶端和服務端發起,它處理來自客戶端的 `XMLHttpRequest`或`Fetch`連接,并通過服務器的 `HTTP2 `將它們轉換為 `gRPC`)`Envoy `作為[`官方gRPC-Web filter`](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/grpc_web_filter)代理,[grpcwebproxy](https://github.com/improbable-eng/grpc-web/tree/master/go/grpcwebproxy)作為 `@ immaybe-eng/grpc-web`代理方案
>[danger] ##### 關于 grpc-web 協議更多細節
* [對于 gRPC-Web 協議規范](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md)
* 在未來`grpc-web` 也將會實現雙向流(`bi-directional streaming`),但并不像`@immaybe-eng/grpc-web` 通過一個實驗性的 `websocket `傳輸支持客戶端和雙向流而會使用[whatwg fetch/streams](https://github.com/whatwg/fetch)截止到`2022.11.7`現在為止現在此實現還沒有成為正式提案
>[danger] ##### 優點
* **端到端 gRPC —** 如上所述,使用 gRPC-Web,您可以正式將 REST 組件從堆棧中刪除,并將其替換為純 gRPC,從而使您能夠使用協議緩沖區來制作?*整個*?RPC 管道。想象一個場景,客戶端請求發送到 HTTP 服務器,然后與 5 個后端 gRPC 服務交互。您很有可能在構建 HTTP 交互層上花費的時間與構建整個管道其余部分的時間一樣多。
* **前端和后端團隊之間更緊密的協調** ?——回想上面的圖表。通過使用 Protocol Buffers 定義整個 RPC 管道,您不再需要將“微服務團隊”與“客戶團隊”放在一起。客戶端-后端交互只是 gRPC 層中的一個。老實說,我還沒有完全理解端到端測試、服務網格集成、持續集成/交付等的含義。
* **輕松生成客戶端庫**?- 使用 gRPC-Web,與“外部”世界交互的服務器,即將后端堆棧連接到互聯網的膜,現在是 gRPC 服務器而不是 HTTP 服務器,這意味著您的所有服務的客戶端庫可以是 gRPC 庫。需要 Ruby、Python、Java 和其他 4 種語言的客戶端庫嗎?您不再需要為所有這些編寫 HTTP 客戶端
>[danger] ##### 缺點
目前因為使用`base64` 進行傳輸實際體積也會變大,例如`1MB` 文件在傳輸過程中發現變成`1.4MB`
>[info] ## 參考
[gRPC-web現狀及測試](http://blog.itpub.net/31559359/viewspace-2637227/)
[# HTTP/2 & gRPC — 高性能 RPC 框架](https://krishnakishorev.medium.com/http-2-grpc-high-performance-rpc-framework-a52722837920)
[# gRPC-Web 通過 HTTP2](https://medium.com/@denis.zhbankov/grpc-web-via-http2-b05c8c8f9e6)
[# 直接在你的 Go 服務器中代理 gRPC-Web](https://medium.com/safetycultureengineering/proxy-grpc-web-directly-in-your-go-server-without-envoy-7fbec326cb21)
[# 使用 gRPC-Web 的優勢](https://www.cncf.io/blog/2018/10/24/grpc-web-is-going-ga/)
[推薦看一下 How to setup and test TLS in gRPC/gRPC-Web | by Alexey Vasyukov | ITNEXT](https://itnext.io/how-to-setup-and-test-tls-in-grpc-grpc-web-1b67cc4413e6)
- 工程化 -- Node
- vscode -- 插件
- vscode -- 代碼片段
- 前端學會調試
- 谷歌瀏覽器調試技巧
- 權限驗證
- 包管理工具 -- npm
- 常見的 npm ci 指令
- npm -- npm install安裝包
- npm -- package.json
- npm -- 查看包版本信息
- npm - package-lock.json
- npm -- node_modules 層級
- npm -- 依賴包規則
- npm -- install 安裝流程
- npx
- npm -- 發布自己的包
- 包管理工具 -- pnpm
- 模擬數據 -- Mock
- 頁面渲染
- 渲染分析
- core.js && babel
- core.js -- 到底是什么
- 編譯器那些術語
- 詞法解析 -- tokenize
- 語法解析 -- ast
- 遍歷節點 -- traverser
- 轉換階段、生成階段略
- babel
- babel -- 初步上手之了解
- babel -- 初步上手之各種配置(preset-env)
- babel -- 初步上手之各種配置@babel/helpers
- babel -- 初步上手之各種配置@babel/runtime
- babel -- 初步上手之各種配置@babel/plugin-transform-runtime
- babel -- 初步上手之各種配置(babel-polyfills )(未來)
- babel -- 初步上手之各種配置 polyfill-service
- babel -- 初步上手之各種配置(@babel/polyfill )(過去式)
- babel -- 總結
- 各種工具
- 前端 -- 工程化
- 了解 -- Yeoman
- 使用 -- Yeoman
- 了解 -- Plop
- node cli -- 開發自己的腳手架工具
- 自動化構建工具
- Gulp
- 模塊化打包工具為什么出現
- 模塊化打包工具(新) -- webpack
- 簡單使用 -- webpack
- 了解配置 -- webpack.config.js
- webpack -- loader 淺解
- loader -- 配置css模塊解析
- loader -- 圖片和字體(4.x)
- loader -- 圖片和字體(5.x)
- loader -- 圖片優化loader
- loader -- 配置解析js/ts
- webpack -- plugins 淺解
- eslit
- plugins -- CleanWebpackPlugin(4.x)
- plugins -- CleanWebpackPlugin(5.x)
- plugin -- HtmlWebpackPlugin
- plugin -- DefinePlugin 注入全局成員
- webapck -- 模塊解析配置
- webpack -- 文件指紋了解
- webpack -- 開發環境運行構建
- webpack -- 項目環境劃分
- 模塊化打包工具 -- webpack
- webpack -- 打包文件是個啥
- webpack -- 基礎配置項用法
- webpack4.x系列學習
- webpack -- 常見loader加載器
- webpack -- 移動端px轉rem處理
- 開發一個自己loader
- webpack -- plugin插件
- webpack -- 文件指紋
- webpack -- 壓縮css和html構建
- webpack -- 清里構建包
- webpack -- 復制靜態文件
- webpack -- 自定義插件
- wepack -- 關于靜態資源內聯
- webpack -- source map 對照包
- webpack -- 環境劃分構建
- webpack -- 項目構建控制臺輸出
- webpack -- 項目分析
- webpack -- 編譯提速優護體積
- 提速 -- 編譯階段
- webpack -- 項目優化
- webpack -- DefinePlugin 注入全局成員
- webpack -- 代碼分割
- webpack -- 頁面資源提取
- webpack -- import按需引入
- webpack -- 搖樹
- webpack -- 多頁面打包
- webpack -- eslint
- webpack -- srr打包后續看
- webpack -- 構建一個自己的配置后續看
- webpack -- 打包組件和基礎庫
- webpack -- 源碼
- webpack -- 啟動都做了什么
- webpack -- cli做了什么
- webpack - 5
- 模塊化打包工具 -- Rollup
- 工程化搭建代碼規范
- 規范化標準--Eslint
- eslint -- 擴展配置
- eslint -- 指令
- eslint -- vscode
- eslint -- 原理
- Prettier -- 格式化代碼工具
- EditorConfig -- 編輯器編碼風格
- 檢查提交代碼是否符合檢查配置
- 整體流程總結
- 微前端
- single-spa
- 簡單上手 -- single-spa
- 快速理解systemjs
- single-sap 不使用systemjs
- monorepo -- 工程
- Vue -- 響應式了解
- Vue2.x -- 源碼分析
- 發布訂閱和觀察者模式
- 簡單 -- 了解響應式模型(一)
- 簡單 -- 了解響應式模型(二)
- 簡單 --了解虛擬DOM(一)
- 簡單 --了解虛擬DOM(二)
- 簡單 --了解diff算法
- 簡單 --了解nextick
- Snabbdom -- 理解虛擬dom和diff算法
- Snabbdom -- h函數
- Snabbdom - Vnode 函數
- Snabbdom -- init 函數
- Snabbdom -- patch 函數
- 手寫 -- 虛擬dom渲染
- Vue -- minVue
- vue3.x -- 源碼分析
- 分析 -- reactivity
- 好文
- grpc -- 瀏覽器使用gRPC
- grcp-web -- 案例
- 待續