transporter/http 中基于 gorilla/mux HTTP路由框架實(shí)現(xiàn)了?Transporter
?,用以注冊(cè) 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í)設(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是怎么實(shí)現(xiàn)的:
func DefaultRequestDecoder(r *http.Request, v interface{}) error {
// 從Request Header的Content-Type中提取出對(duì)應(yīng)的解碼器
codec, ok := CodecForRequest(r, "Content-Type")
// 如果找不到對(duì)應(yīng)的解碼器此時(shí)會(huì)報(bào)錯(cuò)
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
}
那么如果我們想要擴(kuò)展或者替換Content-Type對(duì)應(yīng)的解析實(shí)現(xiàn),就可以通過http.RequestDecoder()來替換kratos默認(rèn)的RequestDecoder, 或者也可以通過在encoding中注冊(cè)或覆蓋一個(gè)Content-Type對(duì)應(yīng)的codec來進(jìn)行擴(kuò)展
ResponseEncoder(en EncodeResponseFunc) ServerOption
?配置kratos服務(wù)端的 HTTP Response Encode方法,用來將用戶pb定義里的reply結(jié)構(gòu)體序列化后寫入Response Body中 我們看下kratos中默認(rèn)的ResponseEncoder是怎么實(shí)現(xiàn)的:
func DefaultResponseEncoder(w http.ResponseWriter, r *http.Request, v interface{}) error {
// 通過Request Header的Accept中提取出對(duì)應(yīng)的編碼器
// 如果找不到則忽略報(bào)錯(cuò),并使用默認(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
}
那么如果我們想要擴(kuò)展或者替換Accept對(duì)應(yīng)的序列化實(shí)現(xiàn),就可以通過http.ResponseEncoder()來替換kratos默認(rèn)的ResponseEncoder, 或者也可以通過在encoding中注冊(cè)或覆蓋一個(gè)Accept對(duì)應(yīng)的codec來進(jìn)行擴(kuò)展
ErrorEncoder(en EncodeErrorFunc) ServerOption
?配置kratos服務(wù)端的 HTTP Error Encode方法,用來將業(yè)務(wù)拋出的error序列化后寫入Response Body中,并設(shè)置HTTP Status Code 我們看下kratos中默認(rèn)的ErrorEncoder是怎么實(shí)現(xiàn)的:
func DefaultErrorEncoder(w http.ResponseWriter, r *http.Request, err error) {
// 拿到error并轉(zhuǎn)換成kratos Error實(shí)體
se := errors.FromError(err)
// 通過Request Header的Accept中提取出對(duì)應(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)建一個(gè)新的HTTP Server Router,同時(shí)可以傳遞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)
?實(shí)現(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
?配置客戶端的請(qǐng)求默認(rèn)超時(shí)時(shí)間,如果有鏈路超時(shí)優(yōu)先使用鏈路超時(shí)時(shí)間
WithUserAgent(ua string) ClientOption
?配置客戶端的默認(rèn)User-Agent
WithMiddleware(m ...middleware.Middleware) ClientOption
?配置客戶端使用的 kratos client中間件
WithEndpoint(endpoint string) ClientOption
?配置客戶端使用的對(duì)端連接地址,如果不使用服務(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)
// 拿到實(shí)際的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是怎么實(shí)現(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拿到對(duì)應(yīng)的decoder
// 然后進(jìn)行Unmarshal
return CodecForResponse(res).Unmarshal(data, v)
}
WithErrorDecoder(errorDecoder DecodeErrorFunc) ClientOption
?配置客戶端的Error解析方法 我們看下kratos中默認(rèn)的error decoder是怎么實(shí)現(xiàn)的:
func DefaultErrorDecoder(ctx context.Context, res *http.Response) error {
// HTTP Status Code 為最高優(yōu)先級(jí)
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拿到對(duì)應(yīng)的response decoder
// 然后解析出error主體內(nèi)容
if err = CodecForResponse(res).Unmarshal(data, e); err == nil {
// HTTP Status Code 為最高優(yōu)先級(jí)
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é)點(diǎn)才返回),默認(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),
)
更多建議: