Dapr Golang HTTP 調用
版本介紹
- Go 版本:1.15
- Dapr Go SKD 版本:0.11.1
工程結構
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5CN4EGZ3ImNzgDZ4IWY5YTZxkDM4czMhZmMklTYwI2Y48CXwEzLcVDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL0M3Lc9CX6MHc0RHaiojIsJye.png)
從上圖可知,建立 3 個 Go 啟動項目,cmd 為啟動項目目錄,其中 client/a/main.go 為用戶端,用于調用服務。service/http/b、service/http/c 為服務項目。調用路徑如下圖所示。建立兩個 service 的意義在于展示 http 鍊路調用通過 dapr 如何實作。
graph LR;
go-client-a--1-->go-service-b;
go-service-b--2-->go-service-c;
go-service-c--3-->go-service-b;
go-service-b--4-->go-client-a;
- go-client-a 做為用戶端調用服務 go-service-b;
- go-service-b 做為服務中轉,既收來自 go-client-a 用戶端的請求,又發起對 go-service-c 的調用;
- go-service-c 響應 go-service-b 的請求;
- go-service-b 響應 go-client-a 的請求。
internal
response.go 檔案,封裝傳回資料。資料結構如下:
package internal
import (
"encoding/json"
"log"
)
type HttpResult struct {
Message string
}
func (r *HttpResult) ToBytes() (bytes []byte) {
var err error
bytes, err = json.Marshal(r)
if err != nil {
log.Fatal("資料轉換失敗")
}
return
}
go-service-c
go-service-c 做為調用鍊路末端,隻需要提供監聽端口,以及綁定路由。下面方法通過
s.AddServiceInvocationHandler("/hello", helloHandler)
方法綁定路由和處理方法。以下為 go-service-c 源碼。
package main
import (
"context"
"errors"
"github.com/Zhang-Byte/dapr-golang/internal"
"github.com/dapr/go-sdk/service/common"
daprd "github.com/dapr/go-sdk/service/http"
"log"
"net/http"
)
func main() {
s := daprd.NewService(":9003")
if err := s.AddServiceInvocationHandler("/hello", helloHandler); err != nil {
log.Fatalf("error adding invocation handler: %v", err)
}
if err := s.Start(); err != nil && err != http.ErrServerClosed {
log.Fatalf("error listenning: %v", err)
}
}
func helloHandler(_ context.Context, in *common.InvocationEvent) (out *common.Content, err error) {
if in == nil {
err = errors.New("invocation parameter required")
return
}
log.Printf("The go-service-c service method hello has been invoked,recieve message is %v", string(in.Data))
httpResult := internal.HttpResult{Message: "This message is from Service C."}
out = &common.Content{
Data: httpResult.ToBytes(),
ContentType: in.ContentType,
DataTypeURL: in.DataTypeURL,
}
return
}
啟動指令:
dapr run --app-id go-service-c \
--app-protocol http \
--app-port 9003 \
--dapr-http-port 3501 \
--log-level debug \
--components-path ./config \
go run ./cmd/service/http/c/main.go
go-service-b
go-service-b 相較于 go-service-c 的代碼來說,添加了初始化用戶端并發送請求的内容。檢視代碼
invokeService()
每次都會調用
client()
,在
client()
中方法看上去每次都會建立一個用戶端,檢視 dapr 源碼注釋可知(Note, this default factory function creates Dapr client only once. All subsequent invocations will return the already created instance. ) 每次隻會傳回已經建立好的執行個體,是以使用完以後不必關閉此用戶端。
package main
import (
"context"
"encoding/json"
"errors"
"github.com/Zhang-Byte/dapr-golang/internal"
dapr "github.com/dapr/go-sdk/client"
"github.com/dapr/go-sdk/service/common"
"log"
"net/http"
)
import daprd "github.com/dapr/go-sdk/service/http"
func main() {
s := daprd.NewService(":9002")
if err := s.AddServiceInvocationHandler("/hello", helloHandler); err != nil {
log.Fatalf("error adding invocation handler: %v", err)
}
if err := s.Start(); err != nil && err != http.ErrServerClosed {
log.Fatalf("error listenning: %v", err)
}
}
func helloHandler(ctx context.Context, in *common.InvocationEvent) (out *common.Content, err error) {
if in == nil {
err = errors.New("invocation parameter required")
return
}
log.Printf("The go-service-b service method hello has been invoked,recieve message is %v", string(in.Data))
msg := invokeService(ctx)
httpResult := internal.HttpResult{Message: msg}
out = &common.Content{
Data: httpResult.ToBytes(),
ContentType: in.ContentType,
DataTypeURL: in.DataTypeURL,
}
return
}
func invokeService(ctx context.Context) (msg string) {
client := client()
content := &dapr.DataContent{
ContentType: "text/plain",
Data: []byte("This is golang Service B."),
}
resp, err := client.InvokeServiceWithContent(ctx, "go-service-c", "hello", content)
if err != nil {
panic(err)
}
var result internal.HttpResult
if err := json.Unmarshal(resp, &result); err != nil {
log.Printf(err.Error())
}
msg = result.Message
return
}
func client() dapr.Client {
client, err := dapr.NewClient()
if err != nil {
panic(err)
}
return client
}
dapr run --app-id go-service-b \
--app-protocol http \
--app-port 9002 \
--dapr-http-port 3500 \
--log-level debug \
--components-path ./config \
go run ./cmd/service/http/b/main.go
go-client-a
最後建立用戶端,用戶端每間隔 5 秒發起一次請求到 go-service-b 。
package main
import (
"context"
dapr "github.com/dapr/go-sdk/client"
"log"
"time"
)
func main() {
ctx := context.Background()
// create the client
client, err := dapr.NewClient()
if err != nil {
panic(err)
}
defer client.Close()
content := &dapr.DataContent{
ContentType: "text/plain",
Data: []byte("This is client A."),
}
for {
resp, err := client.InvokeServiceWithContent(ctx, "go-service-b", "hello", content)
if err != nil {
panic(err)
}
log.Printf("go-service-b method hello has invoked, response: %s", string(resp))
time.Sleep(time.Second * 5)
}
}
dapr run --app-id go-client-a \
--components-path ./config \
--log-level debug \
go run ./cmd/client/a/main.go
總結
client 啟動後,得到傳回值
== APP == 2020/11/06 11:26:41 go-service-b method hello has invoked, response: {"Message":"This message is from Service C."}
go-service-b 列印内容為:
== APP == 2020/11/06 11:31:51 The go-service-b service has been invoked,recieve message is This is client A.
go-service-c 列印内容為:
== APP == 2020/11/06 11:33:31 The go-service-c service method hello has been invoked,recieve message is This is golang Service B.