go微服務系列(四) - http api中引入protobuf

寶樹吶發表於2020-08-27

1. protobuf相關依賴安裝

  • 第一步:下載grpc通用編譯器

如下圖,解壓出來因平臺而異會是一個protoc或者protoc.exe

https://github.com/protocolbuffers/protobuf/releases

  • 第二步:把下載的二進位制檔案路徑新增到環境變數中(為了能全域性訪問protoc)
    • 這裡以為mac為例子
# 開啟這個
vim /etc/paths 

# 把路徑新增進去
/Users/emm/others/protoc-3.12.4-osx-x86_64/bin/protoc

# 重新整理環境變數
source /etc/paths
  • 第三步: 安裝go專用的protoc的生成器
go get github.com/golang/protobuf/protoc-gen-go

安裝後會在GOPATH目錄下生成可執行檔案,protobuf的編譯器外掛protoc-gen-go,等下執行protoc命令會自動呼叫這個外掛

  • 第四步: 安裝go-micro對應的外掛
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修改成具體的型別就可以了

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,如下

只有將客戶端的proto檔案生成的pb.go檔案中的model的tag修改成一樣的才可以

這裡可以使用外掛修改

第一步:下載外掛

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;
}

第三步:使用命令列批量修改

protoc-go-inject-tag -input=../prods.pb.go

相關文章