transporter/http 中基于 gorilla/mux HTTP路由框架實現(xiàn)了?Transporter
?,用以注冊 http 到 ?kratos.Server()
? 中。
Network(network string) ServerOption
?配置服務(wù)端的 network 協(xié)議,如 tcp
Address(addr string) ServerOption
?配置服務(wù)端監(jiān)聽的地址
Timeout(timeout time.Duration) ServerOption
?配置服務(wù)端的超時設(shè)置
Logger(logger log.Logger) ServerOption
?配置服務(wù)端使用日志
Middleware(m ...middleware.Middleware) ServerOption
?配置服務(wù)端的 kratos Service中間件
Filter(filters ...FilterFunc) ServerOption
?配置服務(wù)端的 kratos 全局HTTP原生Fitler,此Filter執(zhí)行順序在Service中間件之前
RequestDecoder(dec DecodeRequestFunc) ServerOption
?配置kratos服務(wù)端的 HTTP Request Decode方法,用來將Request Body解析至用戶定義的pb結(jié)構(gòu)體中 我們看下kratos中默認(rèn)的RequestDecoder是怎么實現(xiàn)的:
func DefaultRequestDecoder(r *http.Request, v interface{}) error {
// 從Request Header的Content-Type中提取出對應(yīng)的解碼器
codec, ok := CodecForRequest(r, "Content-Type")
// 如果找不到對應(yīng)的解碼器此時會報錯
if !ok {
return errors.BadRequest("CODEC", r.Header.Get("Content-Type"))
}
data, err := ioutil.ReadAll(r.Body)
if err != nil {
return errors.BadRequest("CODEC", err.Error())
}
if err = codec.Unmarshal(data, v); err != nil {
return errors.BadRequest("CODEC", err.Error())
}
return nil
}
那么如果我們想要擴展或者替換Content-Type對應(yīng)的解析實現(xiàn),就可以通過http.RequestDecoder()來替換kratos默認(rèn)的RequestDecoder, 或者也可以通過在encoding中注冊或覆蓋一個Content-Type對應(yīng)的codec來進(jìn)行擴展
ResponseEncoder(en EncodeResponseFunc) ServerOption
?配置kratos服務(wù)端的 HTTP Response Encode方法,用來將用戶pb定義里的reply結(jié)構(gòu)體序列化后寫入Response Body中 我們看下kratos中默認(rèn)的ResponseEncoder是怎么實現(xiàn)的:
func DefaultResponseEncoder(w http.ResponseWriter, r *http.Request, v interface{}) error {
// 通過Request Header的Accept中提取出對應(yīng)的編碼器
// 如果找不到則忽略報錯,并使用默認(rèn)json編碼器
codec, _ := CodecForRequest(r, "Accept")
data, err := codec.Marshal(v)
if err != nil {
return err
}
// 在Response Header中寫入編碼器的scheme
w.Header().Set("Content-Type", httputil.ContentType(codec.Name()))
w.Write(data)
return nil
}
那么如果我們想要擴展或者替換Accept對應(yīng)的序列化實現(xiàn),就可以通過http.ResponseEncoder()來替換kratos默認(rèn)的ResponseEncoder, 或者也可以通過在encoding中注冊或覆蓋一個Accept對應(yīng)的codec來進(jìn)行擴展
ErrorEncoder(en EncodeErrorFunc) ServerOption
?配置kratos服務(wù)端的 HTTP Error Encode方法,用來將業(yè)務(wù)拋出的error序列化后寫入Response Body中,并設(shè)置HTTP Status Code 我們看下kratos中默認(rèn)的ErrorEncoder是怎么實現(xiàn)的:
func DefaultErrorEncoder(w http.ResponseWriter, r *http.Request, err error) {
// 拿到error并轉(zhuǎn)換成kratos Error實體
se := errors.FromError(err)
// 通過Request Header的Accept中提取出對應(yīng)的編碼器
codec, _ := CodecForRequest(r, "Accept")
body, err := codec.Marshal(se)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", httputil.ContentType(codec.Name()))
// 設(shè)置HTTP Status Code
w.WriteHeader(int(se.Code))
w.Write(body)
}
??NewServer(opts ...ServerOption) *Server
?
?
hs := http.NewServer()
app := kratos.New(
kratos.Name("kratos"),
kratos.Version("v1.0.0"),
kratos.Server(hs),
)
hs := http.NewServer(
http.Address(":8000"),
http.Middleware(
logging.Server(),
),
)
if tr, ok := transport.FromServerContext(ctx); ok {
kind = tr.Kind().String()
operation = tr.Operation()
// 斷言成HTTP的Transport可以拿到特殊信息
if ht,ok := tr.(*http.Tranport);ok{
fmt.Println(ht.Request())
}
}
func (s *Server) Route(prefix string, filters ...FilterFunc) *Router
?創(chuàng)建一個新的HTTP Server Router,同時可以傳遞kratos的HTTP Filter攔截器 我們看下用法:
r := s.Route("/v1")
r.GET("/helloworld/{name}", _Greeter_SayHello0_HTTP_Handler(srv))
func (s *Server) Handle(path string, h http.Handler)
?將path添加到路由中,并使用標(biāo)準(zhǔn)的HTTP Handler來處理
func (s *Server) HandlePrefix(prefix string, h http.Handler)
?前綴匹配的方式將prefix添加到路由中,并使用標(biāo)準(zhǔn)的HTTP Handler來處理
func (s *Server) ServeHTTP(res http.ResponseWriter, req *http.Request)
?實現(xiàn)了標(biāo)準(zhǔn)庫的HTTP Handler接口
其他路由使用方法參考: https://github.com/go-kratos/examples/tree/main/http/middlewares
在Kratos HTTP中使用gin框架: https://github.com/go-kratos/kratos/blob/main/examples/http/gin/main.go
WithTransport(trans http.RoundTripper) ClientOption
?配置客戶端的HTTP RoundTripper
WithTimeout(d time.Duration) ClientOption
?配置客戶端的請求默認(rèn)超時時間,如果有鏈路超時優(yōu)先使用鏈路超時時間
WithUserAgent(ua string) ClientOption
?配置客戶端的默認(rèn)User-Agent
WithMiddleware(m ...middleware.Middleware) ClientOption
?配置客戶端使用的 kratos client中間件
WithEndpoint(endpoint string) ClientOption
?配置客戶端使用的對端連接地址,如果不使用服務(wù)發(fā)現(xiàn)則為ip:port,如果使用服務(wù)發(fā)現(xiàn)則格式為discovery://\<authority>/\<serviceName>,這里\<authority>可以默認(rèn)填空
WithDiscovery(d registry.Discovery) ClientOption
?配置客戶端使用的服務(wù)發(fā)現(xiàn)
WithRequestEncoder(encoder EncodeRequestFunc) ClientOption
?配置客戶端的 HTTP Request Encode方法,用來將戶定義的pb結(jié)構(gòu)體中序列化至Request Body 我們看下默認(rèn)的encoder:
func DefaultRequestEncoder(ctx context.Context, contentType string, in interface{}) ([]byte, error) {
// 通過外部配置的contentType獲取encoder類型
name := httputil.ContentSubtype(contentType)
// 拿到實際的encoder
body, err := encoding.GetCodec(name).Marshal(in)
if err != nil {
return nil, err
}
return body, err
}
WithResponseDecoder(decoder DecodeResponseFunc) ClientOption
?配置客戶端的 HTTP Response Decode方法,用來將Response Body解析至用戶定義的pb結(jié)構(gòu)體中 我們看下kratos中默認(rèn)的decoder是怎么實現(xiàn)的:
func DefaultResponseDecoder(ctx context.Context, res *http.Response, v interface{}) error {
defer res.Body.Close()
data, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
// 這里根據(jù)Response Header中的Content-Type拿到對應(yīng)的decoder
// 然后進(jìn)行Unmarshal
return CodecForResponse(res).Unmarshal(data, v)
}
WithErrorDecoder(errorDecoder DecodeErrorFunc) ClientOption
?配置客戶端的Error解析方法 我們看下kratos中默認(rèn)的error decoder是怎么實現(xiàn)的:
func DefaultErrorDecoder(ctx context.Context, res *http.Response) error {
// HTTP Status Code 為最高優(yōu)先級
if res.StatusCode >= 200 && res.StatusCode <= 299 {
return nil
}
defer res.Body.Close()
data, err := ioutil.ReadAll(res.Body)
if err == nil {
e := new(errors.Error)
// 這里根據(jù)Response Header中的Content-Type拿到對應(yīng)的response decoder
// 然后解析出error主體內(nèi)容
if err = CodecForResponse(res).Unmarshal(data, e); err == nil {
// HTTP Status Code 為最高優(yōu)先級
e.Code = int32(res.StatusCode)
return e
}
}
// 如果沒有返回合法的Response Body則直接以HTTP Status Code為準(zhǔn)
return errors.Errorf(res.StatusCode, errors.UnknownReason, err.Error())
}
WithBalancer(b balancer.Balancer) ClientOption
?配置客戶端的負(fù)載均衡策略
WithBlock() ClientOption
?配置客戶端的Dial策略為阻塞(直到服務(wù)發(fā)現(xiàn)發(fā)現(xiàn)節(jié)點才返回),默認(rèn)為異步非阻塞
conn, err := http.NewClient(
context.Background(),
http.WithEndpoint("127.0.0.1:8000"),
)
conn, err := http.NewClient(
context.Background(),
http.WithEndpoint("127.0.0.1:9000"),
http.WithMiddleware(
recovery.Recovery(),
),
)
conn, err := http.NewClient(
context.Background(),
http.WithEndpoint("discovery:///helloworld"),
http.WithDiscovery(r),
)
更多建議: