Go-Micro客戶端請求報500錯誤的解決方法
1.服務端程式碼
2.客戶端程式碼
package main import ( "context" "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" "log" ) func main() { consulReg := consul.NewRegistry(registry.Addrs(":8500")) selector := selector.NewSelector( selector.Registry(consulReg), selector.SetStrategy(selector.RoundRobin), ) httpClient := http.NewClient( // 選擇器 client.Selector(selector), // 響應格式預設格式protobuf,設定為json client.ContentType("application/json"), ) req := map[string]string{ } request := httpClient.NewRequest("cas", "/hello", req) rsp := map[string]interface{ }{ } err := httpClient.Call(context.Background(), request, &rsp) if err != nil { log.Fatalf("request err: %+v", err) } log.Printf("%+v",rsp) }
3.發起請求報錯
客戶端請求報錯如下:
{"id":"go.micro.client","code":500,"detail":"none available","status":"Internal Server Error"}
4.問題分析
1.順著客戶端呼叫的Call()
方法,進入原始碼github.com\micro\go-plugins\client\http\http.go
,找到獲取服務節點的方法:
// get next nodes from the selector next, err := h.next(req, callOpts)
2.再繼續檢視next()
方法,找到第63行,這裡為Selector節點選擇器新增了過濾器,傳遞了兩個引數"protocol", "http"
,可以發現是個鍵值對:
3.進一步進入FilterLabel()
方法,在第41行可以發現,上一步傳的兩個引數在這裡做了校驗,分別作為的Metadata(後設資料)
的map的鍵和值,相當於驗證協議需要為http:
if node.Metadata[key] == val { nodes = append(nodes, node) }
4.回到http.go
的69行,如果不滿足http協議,則獲取服務節點失敗,返回我們所遇到的這個err:
到這裡其實已經可以基本確定我們遇到的問題了:在使用go-plugins
外掛進行服務呼叫時,在服務發現時為選擇器新增了過濾,限定了請求協議,要求Metadata
的鍵值必須為"protocol":"http"
,否則返回的服務節點切片長度將為0。
5.解決方法
因此解決方法則是在服務端進行服務註冊的時候,為註冊的服務新增上Metadata
配置,指定請求協議為http:
service := web.NewService( web.Name("cas"), web.Address(":8001"), web.Registry(consulReg), web.Handler(engine), // 為註冊的服務新增Metadata,指定請求協議為http web.Metadata(map[string]string{ "protocol" : "http"}), )