go微服務系列(四) - http api中引入protobuf
阿新 • • 發佈:2020-08-28
- [1. protobuf相關依賴安裝](#head1)
- [2. 改造之前的client](#head2)
- [2.1 新建proto檔案](#head3)
- [2.2 執行protoc命令生成go檔案](#head4)
- [2.3 然後把原來的map修改成具體的型別就可以了](#head5)
- [3. 處理json tag不一致的問題](#head6)
## 1. protobuf相關依賴安裝
- **第一步:下載grpc通用編譯器**
如下圖,解壓出來因平臺而異會是一個`protoc`或者`protoc.exe`
> https://github.com/protocolbuffers/protobuf/releases
![](https://tva1.sinaimg.cn/large/007S8ZIlgy1ghn71b14sxj312l0g0di1.jpg)
- **第二步:把下載的二進位制檔案路徑新增到環境變數中**(為了能全域性訪問protoc)
- 這裡以為mac為例子
```shell
# 開啟這個
vim /etc/paths
# 把路徑新增進去
/Users/emm/others/protoc-3.12.4-osx-x86_64/bin/protoc
# 重新整理環境變數
source /etc/paths
```
- **第三步**: 安裝go專用的protoc的生成器
```shell
go get github.com/golang/protobuf/protoc-gen-go
```
安裝後會在`GOPATH`目錄下生成可執行檔案,protobuf的編譯器外掛`protoc-gen-go`,等下執行`protoc`命令會自動呼叫這個外掛
- **第四步**: 安裝go-micro對應的外掛
```shell
go get github.com/micro/protoc-gen-micro
```
## 2. 改造之前的client
### 2.1 新建proto檔案
- 新建`models/protos`資料夾
- 在上述資料夾下新建`prod.proto`檔案,內容如下:
```
syntax = "proto3";
package Models;
message ProdModel {
int32 Id = 1;
string Name = 2;
}
message ProdRequest {
int32 Size = 1;
}
message ProdListResponse{
repeated ProdModel data = 1;
}
```
### 2.2 執行protoc命令生成go檔案
在`models/protos`資料夾下執行以下命令
```
protoc --micro_out=../ --go_out=../ prods.proto
```
### 2.3 然後把原來的map修改成具體的型別就可以了
```go
package main
import (
"context"
"fmt"
"gomicro-quickstart/goplugin_http_proto_invoker/models"
"log"
"github.com/micro/go-micro/client"
"github.com/micro/go-micro/client/selector"
"github.com/micro/go-micro/registry"
"github.com/micro/go-plugins/client/http"
"github.com/micro/go-plugins/registry/consul"
)
func main() {
// 1. 註冊consul地址
cr := consul.NewRegistry(registry.Addrs("47.100.220.174:8500"))
// 2. 例項化selector
mySelector := selector.NewSelector(
selector.Registry(cr), // 傳入上面的consul
selector.SetStrategy(selector.RoundRobin), // 指定獲取例項的演算法
)
// 3. 請求服務
resp, err := callByGoPlugin(mySelector)
if err != nil {
log.Fatal("request API failed", err)
}
fmt.Printf("[服務呼叫結果]:\r\n %v", resp)
}
func callByGoPlugin(s selector.Selector) ([]*models.ProdModel, error) {
// 1. 呼叫`go-plugins/client/http`包的函式獲取它們提供的httpClient
gopluginClient := http.NewClient(
client.Selector(s), // 傳入上面的selector
client.ContentType("application/json"), // 指定contentType
)
// 2. 新建請求物件,傳入: (1)服務名 (2)endpoint (3)請求引數
req := gopluginClient.NewRequest("ProductService", "/v1/list",
models.ProdRequest{Size: 2})
// 3. 新建響應物件,並call請求,獲取響應
var resp models.ProdListResponse
err := gopluginClient.Call(context.Background(), req, &resp)
if err != nil {
return nil, err
}
return resp.GetData(), nil
}
```
## 3. 處理json tag不一致的問題
如果服務端的model設定了json tag,如下
![](https://tva1.sinaimg.cn/large/007S8ZIlgy1gi5ric9ixzj30iv0bsdgw.jpg)
只有將客戶端的proto檔案生成的`pb.go`檔案中的model的tag修改成一樣的才可以
這裡可以使用外掛修改
**第一步:下載外掛**
```shell
go get -u github.com/favadi/protoc-go-inject-tag
```
**第二步,在proto檔案上加註釋**
```
syntax = "proto3";
package models;
message ProdModel {
// @inject_tag: json:"pid"
int32 Id = 1;
// @inject_tag: json:"pname"
string Name = 2;
}
message ProdRequest {
int32 Size = 1;
}
message ProdListResponse{
repeated ProdModel data = 1;
}
```
**第三步:使用命令列批量修改**
```shell
protoc-go-inject-tag -input=../prods.pb