diff --git a/api/metadata/metadata_http.pb.go b/api/metadata/metadata_http.pb.go index 09c21cf1a..8485c35b3 100644 --- a/api/metadata/metadata_http.pb.go +++ b/api/metadata/metadata_http.pb.go @@ -6,7 +6,6 @@ package metadata import ( context "context" - transport "github.com/go-kratos/kratos/v2/transport" http "github.com/go-kratos/kratos/v2/transport/http" binding "github.com/go-kratos/kratos/v2/transport/http/binding" ) @@ -14,7 +13,6 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the kratos package it is being compiled against. var _ = new(context.Context) -var _ = new(transport.Transporter) var _ = binding.EncodeURL const _ = http.SupportPackageIsVersion1 @@ -36,7 +34,7 @@ func _Metadata_ListServices0_HTTP_Handler(srv MetadataHTTPServer) func(ctx http. if err := ctx.Bind(&in); err != nil { return err } - transport.SetOperation(ctx, "/kratos.api.Metadata/ListServices") + http.SetOperation(ctx, "/kratos.api.Metadata/ListServices") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.ListServices(ctx, req.(*ListServicesRequest)) }) @@ -58,7 +56,7 @@ func _Metadata_GetServiceDesc0_HTTP_Handler(srv MetadataHTTPServer) func(ctx htt if err := ctx.BindVars(&in); err != nil { return err } - transport.SetOperation(ctx, "/kratos.api.Metadata/GetServiceDesc") + http.SetOperation(ctx, "/kratos.api.Metadata/GetServiceDesc") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.GetServiceDesc(ctx, req.(*GetServiceDescRequest)) }) diff --git a/cmd/protoc-gen-go-http/http.go b/cmd/protoc-gen-go-http/http.go index d4d3288fd..0b18a29a4 100644 --- a/cmd/protoc-gen-go-http/http.go +++ b/cmd/protoc-gen-go-http/http.go @@ -12,7 +12,6 @@ import ( const ( contextPackage = protogen.GoImportPath("context") - transportPackage = protogen.GoImportPath("github.com/go-kratos/kratos/v2/transport") transportHTTPPackage = protogen.GoImportPath("github.com/go-kratos/kratos/v2/transport/http") bindingPackage = protogen.GoImportPath("github.com/go-kratos/kratos/v2/transport/http/binding") ) @@ -44,7 +43,6 @@ func generateFileContent(gen *protogen.Plugin, file *protogen.File, g *protogen. g.P("// This is a compile-time assertion to ensure that this generated file") g.P("// is compatible with the kratos package it is being compiled against.") g.P("var _ = new(", contextPackage.Ident("Context"), ")") - g.P("var _ = new(", transportPackage.Ident("Transporter"), ")") g.P("var _ = ", bindingPackage.Ident("EncodeURL")) g.P("const _ = ", transportHTTPPackage.Ident("SupportPackageIsVersion1")) g.P() diff --git a/cmd/protoc-gen-go-http/template.go b/cmd/protoc-gen-go-http/template.go index 425519999..4a3130990 100644 --- a/cmd/protoc-gen-go-http/template.go +++ b/cmd/protoc-gen-go-http/template.go @@ -34,7 +34,7 @@ func _{{$svrType}}_{{.Name}}{{.Num}}_HTTP_Handler(srv {{$svrType}}HTTPServer) fu return err } {{- end}} - transport.SetOperation(ctx,"/{{$svrName}}/{{.Name}}") + http.SetOperation(ctx,"/{{$svrName}}/{{.Name}}") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.{{.Name}}(ctx, req.(*{{.Request}})) }) diff --git a/examples/blog/api/blog/v1/blog_http.pb.go b/examples/blog/api/blog/v1/blog_http.pb.go index 4aef7f9e8..3fcd414d3 100644 --- a/examples/blog/api/blog/v1/blog_http.pb.go +++ b/examples/blog/api/blog/v1/blog_http.pb.go @@ -6,7 +6,6 @@ package v1 import ( context "context" - transport "github.com/go-kratos/kratos/v2/transport" http "github.com/go-kratos/kratos/v2/transport/http" binding "github.com/go-kratos/kratos/v2/transport/http/binding" ) @@ -14,7 +13,6 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the kratos package it is being compiled against. var _ = new(context.Context) -var _ = new(transport.Transporter) var _ = binding.EncodeURL const _ = http.SupportPackageIsVersion1 @@ -42,7 +40,7 @@ func _BlogService_CreateArticle0_HTTP_Handler(srv BlogServiceHTTPServer) func(ct if err := ctx.Bind(&in); err != nil { return err } - transport.SetOperation(ctx, "/blog.api.v1.BlogService/CreateArticle") + http.SetOperation(ctx, "/blog.api.v1.BlogService/CreateArticle") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.CreateArticle(ctx, req.(*CreateArticleRequest)) }) @@ -64,7 +62,7 @@ func _BlogService_UpdateArticle0_HTTP_Handler(srv BlogServiceHTTPServer) func(ct if err := ctx.BindVars(&in); err != nil { return err } - transport.SetOperation(ctx, "/blog.api.v1.BlogService/UpdateArticle") + http.SetOperation(ctx, "/blog.api.v1.BlogService/UpdateArticle") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.UpdateArticle(ctx, req.(*UpdateArticleRequest)) }) @@ -86,7 +84,7 @@ func _BlogService_DeleteArticle0_HTTP_Handler(srv BlogServiceHTTPServer) func(ct if err := ctx.BindVars(&in); err != nil { return err } - transport.SetOperation(ctx, "/blog.api.v1.BlogService/DeleteArticle") + http.SetOperation(ctx, "/blog.api.v1.BlogService/DeleteArticle") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.DeleteArticle(ctx, req.(*DeleteArticleRequest)) }) @@ -108,7 +106,7 @@ func _BlogService_GetArticle0_HTTP_Handler(srv BlogServiceHTTPServer) func(ctx h if err := ctx.BindVars(&in); err != nil { return err } - transport.SetOperation(ctx, "/blog.api.v1.BlogService/GetArticle") + http.SetOperation(ctx, "/blog.api.v1.BlogService/GetArticle") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.GetArticle(ctx, req.(*GetArticleRequest)) }) @@ -127,7 +125,7 @@ func _BlogService_ListArticle0_HTTP_Handler(srv BlogServiceHTTPServer) func(ctx if err := ctx.Bind(&in); err != nil { return err } - transport.SetOperation(ctx, "/blog.api.v1.BlogService/ListArticle") + http.SetOperation(ctx, "/blog.api.v1.BlogService/ListArticle") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.ListArticle(ctx, req.(*ListArticleRequest)) }) diff --git a/examples/helloworld/helloworld/helloworld_http.pb.go b/examples/helloworld/helloworld/helloworld_http.pb.go index e20130e3f..555173382 100644 --- a/examples/helloworld/helloworld/helloworld_http.pb.go +++ b/examples/helloworld/helloworld/helloworld_http.pb.go @@ -6,7 +6,6 @@ package helloworld import ( context "context" - transport "github.com/go-kratos/kratos/v2/transport" http "github.com/go-kratos/kratos/v2/transport/http" binding "github.com/go-kratos/kratos/v2/transport/http/binding" ) @@ -14,7 +13,6 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the kratos package it is being compiled against. var _ = new(context.Context) -var _ = new(transport.Transporter) var _ = binding.EncodeURL const _ = http.SupportPackageIsVersion1 @@ -37,7 +35,7 @@ func _Greeter_SayHello0_HTTP_Handler(srv GreeterHTTPServer) func(ctx http.Contex if err := ctx.BindVars(&in); err != nil { return err } - transport.SetOperation(ctx, "/helloworld.Greeter/SayHello") + http.SetOperation(ctx, "/helloworld.Greeter/SayHello") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.SayHello(ctx, req.(*HelloRequest)) }) diff --git a/examples/http/middlewares/handlers.go b/examples/http/middlewares/handlers.go index dce1ed2cf..08950ecef 100644 --- a/examples/http/middlewares/handlers.go +++ b/examples/http/middlewares/handlers.go @@ -4,7 +4,6 @@ import ( "context" "github.com/go-kratos/kratos/examples/helloworld/helloworld" - "github.com/go-kratos/kratos/v2/transport" "github.com/go-kratos/kratos/v2/transport/http" ) @@ -19,7 +18,7 @@ func sayHelloHandler(ctx http.Context) error { return err } - transport.SetOperation(ctx, "/helloworld.Greeter/SayHello") + http.SetOperation(ctx, "/helloworld.Greeter/SayHello") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return &helloworld.HelloReply{Message: "test:" + req.(*helloworld.HelloRequest).Name}, nil }) diff --git a/examples/metadata/client/main.go b/examples/metadata/client/main.go index 2499c432d..d3248b815 100644 --- a/examples/metadata/client/main.go +++ b/examples/metadata/client/main.go @@ -6,11 +6,9 @@ import ( "github.com/go-kratos/kratos/examples/helloworld/helloworld" "github.com/go-kratos/kratos/v2/metadata" - "github.com/go-kratos/kratos/v2/middleware" - "github.com/go-kratos/kratos/v2/middleware/recovery" + mmd "github.com/go-kratos/kratos/v2/middleware/metadata" "github.com/go-kratos/kratos/v2/transport/grpc" "github.com/go-kratos/kratos/v2/transport/http" - grpcmd "google.golang.org/grpc/metadata" ) func main() { @@ -22,7 +20,7 @@ func callHTTP() { conn, err := http.NewClient( context.Background(), http.WithMiddleware( - recovery.Recovery(), + mmd.Client(), ), http.WithEndpoint("127.0.0.1:8000"), ) @@ -30,12 +28,9 @@ func callHTTP() { panic(err) } client := helloworld.NewGreeterHTTPClient(conn) - md := metadata.Metadata{"kratos-extra": "2233"} - reply, err := client.SayHello(context.Background(), - &helloworld.HelloRequest{Name: "kratos"}, - // call options - http.Metadata(md), - ) + ctx := context.Background() + ctx = metadata.AppendToClientContext(ctx, "x-md-global-extra", "2233") + reply, err := client.SayHello(ctx, &helloworld.HelloRequest{Name: "kratos"}) if err != nil { log.Fatal(err) } @@ -47,16 +42,15 @@ func callGRPC() { context.Background(), grpc.WithEndpoint("127.0.0.1:9000"), grpc.WithMiddleware( - middleware.Chain( - recovery.Recovery(), - ), + mmd.Client(), ), ) if err != nil { log.Fatal(err) } client := helloworld.NewGreeterClient(conn) - ctx := grpcmd.AppendToOutgoingContext(context.Background(), "kratos-extra", "2233") + ctx := context.Background() + ctx = metadata.AppendToClientContext(ctx, "x-md-global-extra", "2233") reply, err := client.SayHello(ctx, &helloworld.HelloRequest{Name: "kratos"}) if err != nil { log.Fatal(err) diff --git a/examples/metadata/server/main.go b/examples/metadata/server/main.go index 67e35e0ab..e7cab1c42 100644 --- a/examples/metadata/server/main.go +++ b/examples/metadata/server/main.go @@ -7,8 +7,8 @@ import ( "github.com/go-kratos/kratos/examples/helloworld/helloworld" "github.com/go-kratos/kratos/v2" - "github.com/go-kratos/kratos/v2/middleware/recovery" - "github.com/go-kratos/kratos/v2/transport" + "github.com/go-kratos/kratos/v2/metadata" + mmd "github.com/go-kratos/kratos/v2/middleware/metadata" "github.com/go-kratos/kratos/v2/transport/grpc" "github.com/go-kratos/kratos/v2/transport/http" ) @@ -29,8 +29,8 @@ type server struct { // SayHello implements helloworld.GreeterServer func (s *server) SayHello(ctx context.Context, in *helloworld.HelloRequest) (*helloworld.HelloReply, error) { var extra string - if tr, ok := transport.FromServerContext(ctx); ok { - extra = tr.Metadata().Get("kratos-extra") + if md, ok := metadata.FromServerContext(ctx); ok { + extra = md.Get("x-md-global-extra") } return &helloworld.HelloReply{Message: fmt.Sprintf("Hello %s and %s", in.Name, extra)}, nil } @@ -39,12 +39,12 @@ func main() { grpcSrv := grpc.NewServer( grpc.Address(":9000"), grpc.Middleware( - recovery.Recovery(), + mmd.Server(), )) httpSrv := http.NewServer( http.Address(":8000"), http.Middleware( - recovery.Recovery(), + mmd.Server(), ), ) diff --git a/examples/traces/api/message/message_http.pb.go b/examples/traces/api/message/message_http.pb.go index 40ad223da..bfa19083c 100644 --- a/examples/traces/api/message/message_http.pb.go +++ b/examples/traces/api/message/message_http.pb.go @@ -6,7 +6,6 @@ package v1 import ( context "context" - transport "github.com/go-kratos/kratos/v2/transport" http "github.com/go-kratos/kratos/v2/transport/http" binding "github.com/go-kratos/kratos/v2/transport/http/binding" ) @@ -14,7 +13,6 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the kratos package it is being compiled against. var _ = new(context.Context) -var _ = new(transport.Transporter) var _ = binding.EncodeURL const _ = http.SupportPackageIsVersion1 @@ -37,7 +35,7 @@ func _MessageService_GetUserMessage0_HTTP_Handler(srv MessageServiceHTTPServer) if err := ctx.BindVars(&in); err != nil { return err } - transport.SetOperation(ctx, "/api.message.v1.MessageService/GetUserMessage") + http.SetOperation(ctx, "/api.message.v1.MessageService/GetUserMessage") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.GetUserMessage(ctx, req.(*GetUserMessageRequest)) }) diff --git a/examples/traces/api/user/user_http.pb.go b/examples/traces/api/user/user_http.pb.go index cf26c3f2a..758b45604 100644 --- a/examples/traces/api/user/user_http.pb.go +++ b/examples/traces/api/user/user_http.pb.go @@ -6,7 +6,6 @@ package v1 import ( context "context" - transport "github.com/go-kratos/kratos/v2/transport" http "github.com/go-kratos/kratos/v2/transport/http" binding "github.com/go-kratos/kratos/v2/transport/http/binding" ) @@ -14,7 +13,6 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the kratos package it is being compiled against. var _ = new(context.Context) -var _ = new(transport.Transporter) var _ = binding.EncodeURL const _ = http.SupportPackageIsVersion1 @@ -37,7 +35,7 @@ func _User_GetMyMessages0_HTTP_Handler(srv UserHTTPServer) func(ctx http.Context if err := ctx.BindVars(&in); err != nil { return err } - transport.SetOperation(ctx, "/api.user.v1.User/GetMyMessages") + http.SetOperation(ctx, "/api.user.v1.User/GetMyMessages") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.GetMyMessages(ctx, req.(*GetMyMessagesRequest)) }) diff --git a/internal/testproto/echo_service_http.pb.go b/internal/testproto/echo_service_http.pb.go index feca7ea2e..819db2c8b 100644 --- a/internal/testproto/echo_service_http.pb.go +++ b/internal/testproto/echo_service_http.pb.go @@ -6,7 +6,6 @@ package testproto import ( context "context" - transport "github.com/go-kratos/kratos/v2/transport" http "github.com/go-kratos/kratos/v2/transport/http" binding "github.com/go-kratos/kratos/v2/transport/http/binding" ) @@ -14,7 +13,6 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the kratos package it is being compiled against. var _ = new(context.Context) -var _ = new(transport.Transporter) var _ = binding.EncodeURL const _ = http.SupportPackageIsVersion1 @@ -49,7 +47,7 @@ func _EchoService_Echo0_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Co if err := ctx.BindVars(&in); err != nil { return err } - transport.SetOperation(ctx, "/testproto.EchoService/Echo") + http.SetOperation(ctx, "/testproto.EchoService/Echo") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.Echo(ctx, req.(*SimpleMessage)) }) @@ -71,7 +69,7 @@ func _EchoService_Echo1_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Co if err := ctx.BindVars(&in); err != nil { return err } - transport.SetOperation(ctx, "/testproto.EchoService/Echo") + http.SetOperation(ctx, "/testproto.EchoService/Echo") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.Echo(ctx, req.(*SimpleMessage)) }) @@ -93,7 +91,7 @@ func _EchoService_Echo2_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Co if err := ctx.BindVars(&in); err != nil { return err } - transport.SetOperation(ctx, "/testproto.EchoService/Echo") + http.SetOperation(ctx, "/testproto.EchoService/Echo") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.Echo(ctx, req.(*SimpleMessage)) }) @@ -115,7 +113,7 @@ func _EchoService_Echo3_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Co if err := ctx.BindVars(&in); err != nil { return err } - transport.SetOperation(ctx, "/testproto.EchoService/Echo") + http.SetOperation(ctx, "/testproto.EchoService/Echo") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.Echo(ctx, req.(*SimpleMessage)) }) @@ -137,7 +135,7 @@ func _EchoService_Echo4_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Co if err := ctx.BindVars(&in); err != nil { return err } - transport.SetOperation(ctx, "/testproto.EchoService/Echo") + http.SetOperation(ctx, "/testproto.EchoService/Echo") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.Echo(ctx, req.(*SimpleMessage)) }) @@ -156,7 +154,7 @@ func _EchoService_EchoBody0_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx htt if err := ctx.Bind(&in); err != nil { return err } - transport.SetOperation(ctx, "/testproto.EchoService/EchoBody") + http.SetOperation(ctx, "/testproto.EchoService/EchoBody") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.EchoBody(ctx, req.(*SimpleMessage)) }) @@ -175,7 +173,7 @@ func _EchoService_EchoResponseBody0_HTTP_Handler(srv EchoServiceHTTPServer) func if err := ctx.Bind(&in); err != nil { return err } - transport.SetOperation(ctx, "/testproto.EchoService/EchoResponseBody") + http.SetOperation(ctx, "/testproto.EchoService/EchoResponseBody") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.EchoResponseBody(ctx, req.(*DynamicMessageUpdate)) }) @@ -197,7 +195,7 @@ func _EchoService_EchoDelete0_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx h if err := ctx.BindVars(&in); err != nil { return err } - transport.SetOperation(ctx, "/testproto.EchoService/EchoDelete") + http.SetOperation(ctx, "/testproto.EchoService/EchoDelete") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.EchoDelete(ctx, req.(*SimpleMessage)) }) @@ -216,7 +214,7 @@ func _EchoService_EchoPatch0_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx ht if err := ctx.Bind(&in.Body); err != nil { return err } - transport.SetOperation(ctx, "/testproto.EchoService/EchoPatch") + http.SetOperation(ctx, "/testproto.EchoService/EchoPatch") h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) { return srv.EchoPatch(ctx, req.(*DynamicMessageUpdate)) }) diff --git a/internal/testproto/echo_service_test.go b/internal/testproto/echo_service_test.go index 3621cfc3c..373c76196 100644 --- a/internal/testproto/echo_service_test.go +++ b/internal/testproto/echo_service_test.go @@ -9,23 +9,22 @@ import ( "github.com/go-kratos/kratos/v2/encoding" "github.com/go-kratos/kratos/v2/metadata" - "github.com/go-kratos/kratos/v2/transport" + mmd "github.com/go-kratos/kratos/v2/middleware/metadata" "github.com/go-kratos/kratos/v2/transport/grpc" "github.com/go-kratos/kratos/v2/transport/http" _struct "github.com/golang/protobuf/ptypes/struct" - grpcmd "google.golang.org/grpc/metadata" ) -var md = metadata.Metadata{"test_key": "test_value"} +var md = metadata.Metadata{"x-md-global-test": "test_value"} type echoService struct { UnimplementedEchoServiceServer } func (s *echoService) Echo(ctx context.Context, m *SimpleMessage) (*SimpleMessage, error) { - md := transport.Metadata(ctx) - if v := md.Get("test_key"); v != "test_value" { + md, _ := metadata.FromServerContext(ctx) + if v := md.Get("x-md-global-test"); v != "test_value" { return nil, errors.New("md not match" + v) } return m, nil @@ -53,7 +52,7 @@ type echoClient struct { // post: /v1/example/echo/{id} func (c *echoClient) Echo(ctx context.Context, in *SimpleMessage) (out *SimpleMessage, err error) { - return c.client.Echo(ctx, in, http.Metadata(md)) + return c.client.Echo(ctx, in) } // post: /v1/example/echo_body @@ -104,7 +103,10 @@ func TestJSON(t *testing.T) { func TestEchoHTTPServer(t *testing.T) { echo := &echoService{} ctx := context.Background() - srv := http.NewServer(http.Address(":2333")) + srv := http.NewServer( + http.Address(":2333"), + http.Middleware(mmd.Server()), + ) RegisterEchoServiceHTTPServer(srv, echo) go func() { if err := srv.Start(ctx); err != nil { @@ -127,11 +129,16 @@ func testEchoHTTPClient(t *testing.T, addr string) { t.Errorf("[%s] expected %v got %v", name, in, out) } } - cc, _ := http.NewClient(context.Background(), http.WithEndpoint(addr)) + cc, _ := http.NewClient(context.Background(), + http.WithEndpoint(addr), + http.WithMiddleware(mmd.Client()), + ) cli := &echoClient{client: NewEchoServiceHTTPClient(cc)} - if out, err = cli.Echo(context.Background(), in); err != nil { + ctx := context.Background() + ctx = metadata.NewClientContext(ctx, md) + if out, err = cli.Echo(ctx, in); err != nil { t.Fatal(err) } check("echo", &SimpleMessage{Id: "test_id"}, out) @@ -173,7 +180,10 @@ func testEchoHTTPClient(t *testing.T, addr string) { func TestEchoGRPCServer(t *testing.T) { echo := &echoService{} ctx := context.Background() - srv := grpc.NewServer(grpc.Address(":2233")) + srv := grpc.NewServer( + grpc.Address(":2233"), + grpc.Middleware(mmd.Server()), + ) RegisterEchoServiceServer(srv, echo) go func() { if err := srv.Start(ctx); err != nil { @@ -186,8 +196,11 @@ func TestEchoGRPCServer(t *testing.T) { } func testEchoGRPCClient(t *testing.T, addr string) { - ctx := context.Background() - cc, err := grpc.DialInsecure(ctx, grpc.WithEndpoint(addr)) + cc, err := grpc.DialInsecure( + context.Background(), + grpc.WithEndpoint(addr), + grpc.WithMiddleware(mmd.Client()), + ) if err != nil { t.Fatal(err) } @@ -196,7 +209,8 @@ func testEchoGRPCClient(t *testing.T, addr string) { out = &SimpleMessage{} ) client := NewEchoServiceClient(cc) - ctx = grpcmd.NewOutgoingContext(ctx, grpcmd.New(md)) + ctx := context.Background() + ctx = metadata.NewClientContext(ctx, md) if out, err = client.Echo(ctx, in); err != nil { t.Fatal(err) } diff --git a/metadata/context.go b/metadata/context.go new file mode 100644 index 000000000..e05a37759 --- /dev/null +++ b/metadata/context.go @@ -0,0 +1,46 @@ +package metadata + +import ( + "context" + "fmt" +) + +type serverMetadataKey struct{} + +// NewServerContext creates a new context with client md attached. +func NewServerContext(ctx context.Context, md Metadata) context.Context { + return context.WithValue(ctx, serverMetadataKey{}, md) +} + +// FromServerContext returns the server metadata in ctx if it exists. +func FromServerContext(ctx context.Context) (Metadata, bool) { + md, ok := ctx.Value(serverMetadataKey{}).(Metadata) + return md, ok +} + +type clientMetadataKey struct{} + +// NewClientContext creates a new context with client md attached. +func NewClientContext(ctx context.Context, md Metadata) context.Context { + return context.WithValue(ctx, clientMetadataKey{}, md) +} + +// FromClientContext returns the client metadata in ctx if it exists. +func FromClientContext(ctx context.Context) (Metadata, bool) { + md, ok := ctx.Value(clientMetadataKey{}).(Metadata) + return md, ok +} + +// AppendToClientContext returns a new context with the provided kv merged +// with any existing metadata in the context. +func AppendToClientContext(ctx context.Context, kv ...string) context.Context { + if len(kv)%2 == 1 { + panic(fmt.Sprintf("metadata: AppendToOutgoingContext got an odd number of input pairs for metadata: %d", len(kv))) + } + md, _ := FromClientContext(ctx) + md = md.Clone() + for i := 0; i < len(kv); i += 2 { + md.Set(kv[i], kv[i+1]) + } + return NewClientContext(ctx, md) +} diff --git a/metadata/metadata.go b/metadata/metadata.go index 445886fb6..7cc225f24 100644 --- a/metadata/metadata.go +++ b/metadata/metadata.go @@ -10,15 +10,17 @@ import ( type Metadata map[string]string // New creates an MD from a given key-values map. -func New(m map[string][]string) Metadata { +func New(mds ...map[string]string) Metadata { md := Metadata{} - for k, v := range m { - if k == "" { - continue - } - key := strings.ToLower(k) - if len(v) > 0 && v[0] != "" { - md[key] = v[0] + for _, m := range mds { + for k, v := range m { + if k == "" { + continue + } + key := strings.ToLower(k) + if len(v) > 0 && v != "" { + md[key] = v + } } } return md @@ -39,24 +41,6 @@ func (m Metadata) Set(key string, value string) { m[k] = value } -// Keys lists the keys stored in this carrier. -func (m Metadata) Keys() []string { - keys := make([]string, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - return keys -} - -// Pairs returns all metadata to key/value pairs. -func (m Metadata) Pairs() []string { - var kvs = make([]string, 0, len(m)*2) - for k, v := range m { - kvs = append(kvs, k, v) - } - return kvs -} - // Clone returns a deep copy of Metadata func (m Metadata) Clone() Metadata { md := Metadata{} diff --git a/middleware/logging/logging_test.go b/middleware/logging/logging_test.go index 104c6570c..e08d9db52 100644 --- a/middleware/logging/logging_test.go +++ b/middleware/logging/logging_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/go-kratos/kratos/v2/log" - "github.com/go-kratos/kratos/v2/metadata" "github.com/go-kratos/kratos/v2/middleware" "github.com/go-kratos/kratos/v2/transport" ) @@ -34,18 +33,10 @@ func (tr *Transport) Operation() string { return tr.operation } -func (tr *Transport) SetOperation(operation string) { - tr.operation = operation -} - -func (tr *Transport) Metadata() metadata.Metadata { +func (tr *Transport) Header() transport.Header { return nil } -func (tr *Transport) WithMetadata(md metadata.Metadata) { - -} - func TestHTTP(t *testing.T) { var err = errors.New("reply.error") var bf = bytes.NewBuffer(nil) diff --git a/middleware/metadata/metadata.go b/middleware/metadata/metadata.go new file mode 100644 index 000000000..ac1e76ed0 --- /dev/null +++ b/middleware/metadata/metadata.go @@ -0,0 +1,95 @@ +package metadata + +import ( + "context" + "strings" + + "github.com/go-kratos/kratos/v2/metadata" + "github.com/go-kratos/kratos/v2/middleware" + "github.com/go-kratos/kratos/v2/transport" +) + +// Option is metadata option. +type Option func(*options) + +type options struct { + prefix []string + md metadata.Metadata +} + +// WithConstants is option with constant metadata key value. +func WithConstants(md metadata.Metadata) Option { + return func(o *options) { + o.md = md + } +} + +// WithPropagatedPrefix is option with global propagated key prefix. +func WithPropagatedPrefix(prefix ...string) Option { + return func(o *options) { + o.prefix = prefix + } +} + +// Server is middleware client-side metadata. +func Server(opts ...Option) middleware.Middleware { + options := options{ + prefix: []string{"x-md-global-", "x-md-local-"}, + } + for _, o := range opts { + o(&options) + } + return func(handler middleware.Handler) middleware.Handler { + return func(ctx context.Context, req interface{}) (reply interface{}, err error) { + if tr, ok := transport.FromServerContext(ctx); ok { + md := metadata.Metadata{} + for _, k := range tr.Header().Keys() { + key := strings.ToLower(k) + for _, prefix := range options.prefix { + if strings.HasPrefix(key, prefix) { + md.Set(k, tr.Header().Get(k)) + break + } + } + } + ctx = metadata.NewServerContext(ctx, md) + } + return handler(ctx, req) + } + } +} + +// Client is middleware client-side metadata. +func Client(opts ...Option) middleware.Middleware { + options := options{ + prefix: []string{"x-md-global-"}, + } + for _, o := range opts { + o(&options) + } + return func(handler middleware.Handler) middleware.Handler { + return func(ctx context.Context, req interface{}) (reply interface{}, err error) { + if tr, ok := transport.FromClientContext(ctx); ok { + for k, v := range options.md { + tr.Header().Set(k, v) + } + if md, ok := metadata.FromClientContext(ctx); ok { + for k, v := range md { + tr.Header().Set(k, v) + } + } + if md, ok := metadata.FromServerContext(ctx); ok { + for k, v := range md { + for _, prefix := range options.prefix { + if strings.HasPrefix(k, prefix) { + tr.Header().Set(k, v) + break + } + } + } + } + } + return handler(ctx, req) + } + } +} diff --git a/middleware/tracing/tracing.go b/middleware/tracing/tracing.go index 2b3f385df..bc5e70db2 100644 --- a/middleware/tracing/tracing.go +++ b/middleware/tracing/tracing.go @@ -38,7 +38,7 @@ func Server(opts ...Option) middleware.Middleware { return func(ctx context.Context, req interface{}) (reply interface{}, err error) { if tr, ok := transport.FromServerContext(ctx); ok { var span trace.Span - ctx, span = tracer.Start(ctx, tr.Kind(), tr.Operation(), tr.Metadata()) + ctx, span = tracer.Start(ctx, tr.Kind(), tr.Operation(), tr.Header()) defer func() { tracer.End(ctx, span, err) }() } return handler(ctx, req) @@ -53,7 +53,7 @@ func Client(opts ...Option) middleware.Middleware { return func(ctx context.Context, req interface{}) (reply interface{}, err error) { if tr, ok := transport.FromClientContext(ctx); ok { var span trace.Span - ctx, span = tracer.Start(ctx, tr.Kind(), tr.Operation(), tr.Metadata()) + ctx, span = tracer.Start(ctx, tr.Kind(), tr.Operation(), tr.Header()) defer func() { tracer.End(ctx, span, err) }() } return handler(ctx, req) diff --git a/transport/grpc/client.go b/transport/grpc/client.go index 55d6e7f20..58cbe9508 100644 --- a/transport/grpc/client.go +++ b/transport/grpc/client.go @@ -4,7 +4,6 @@ import ( "context" "time" - "github.com/go-kratos/kratos/v2/metadata" "github.com/go-kratos/kratos/v2/middleware" "github.com/go-kratos/kratos/v2/registry" "github.com/go-kratos/kratos/v2/transport" @@ -117,7 +116,7 @@ func unaryClientInterceptor(ms []middleware.Middleware, timeout time.Duration) g ctx = transport.NewClientContext(ctx, &Transport{ endpoint: cc.Target(), operation: method, - metadata: metadata.Metadata{}, + header: headerCarrier{}, }) if timeout > 0 { var cancel context.CancelFunc @@ -126,7 +125,12 @@ func unaryClientInterceptor(ms []middleware.Middleware, timeout time.Duration) g } h := func(ctx context.Context, req interface{}) (interface{}, error) { if tr, ok := transport.FromClientContext(ctx); ok { - ctx = grpcmd.AppendToOutgoingContext(ctx, tr.Metadata().Pairs()...) + keys := tr.Header().Keys() + keyvals := make([]string, 0, len(keys)) + for _, k := range keys { + keyvals = append(keyvals, k, tr.Header().Get(k)) + } + ctx = grpcmd.AppendToOutgoingContext(ctx, keyvals...) } return reply, invoker(ctx, method, req, reply, cc, opts...) } diff --git a/transport/grpc/server.go b/transport/grpc/server.go index e6c6bf3af..5710c8244 100644 --- a/transport/grpc/server.go +++ b/transport/grpc/server.go @@ -11,7 +11,6 @@ import ( ic "github.com/go-kratos/kratos/v2/internal/context" "github.com/go-kratos/kratos/v2/internal/host" "github.com/go-kratos/kratos/v2/log" - "github.com/go-kratos/kratos/v2/metadata" "github.com/go-kratos/kratos/v2/middleware" "github.com/go-kratos/kratos/v2/transport" @@ -181,7 +180,7 @@ func (s *Server) unaryServerInterceptor() grpc.UnaryServerInterceptor { ctx = transport.NewServerContext(ctx, &Transport{ endpoint: s.endpoint.String(), operation: info.FullMethod, - metadata: metadata.New(md), + header: headerCarrier(md), }) if s.timeout > 0 { var cancel context.CancelFunc diff --git a/transport/grpc/transport.go b/transport/grpc/transport.go index 89bed23bb..80814f581 100644 --- a/transport/grpc/transport.go +++ b/transport/grpc/transport.go @@ -1,8 +1,8 @@ package grpc import ( - "github.com/go-kratos/kratos/v2/metadata" "github.com/go-kratos/kratos/v2/transport" + "google.golang.org/grpc/metadata" ) var ( @@ -13,7 +13,7 @@ var ( type Transport struct { endpoint string operation string - metadata metadata.Metadata + header headerCarrier } // Kind returns the transport kind. @@ -31,19 +31,32 @@ func (tr *Transport) Operation() string { return tr.operation } -// SetOperation sets the transport operation. -func (tr *Transport) SetOperation(operation string) { - tr.operation = operation +// Header returns the transport header. +func (tr *Transport) Header() transport.Header { + return tr.header } -// Metadata returns the transport metadata. -func (tr *Transport) Metadata() metadata.Metadata { - return tr.metadata -} +type headerCarrier metadata.MD -// WithMetadata with a metadata into transport md. -func (tr *Transport) WithMetadata(md metadata.Metadata) { - for k, v := range md { - tr.metadata.Set(k, v) +// Get returns the value associated with the passed key. +func (mc headerCarrier) Get(key string) string { + vals := metadata.MD(mc).Get(key) + if len(vals) > 0 { + return vals[0] } + return "" +} + +// Set stores the key-value pair. +func (mc headerCarrier) Set(key string, value string) { + metadata.MD(mc).Set(key, value) +} + +// Keys lists the keys stored in this carrier. +func (mc headerCarrier) Keys() []string { + keys := make([]string, 0, len(mc)) + for k := range metadata.MD(mc) { + keys = append(keys, k) + } + return keys } diff --git a/transport/http/calloption.go b/transport/http/calloption.go index b2f6b0432..cd2cd72cf 100644 --- a/transport/http/calloption.go +++ b/transport/http/calloption.go @@ -1,7 +1,5 @@ package http -import "github.com/go-kratos/kratos/v2/metadata" - // CallOption configures a Call before it starts or extracts information from // a Call after it completes. type CallOption interface { @@ -17,7 +15,6 @@ type CallOption interface { type callInfo struct { contentType string operation string - metatada metadata.Metadata } // EmptyCallOption does not alter the Call configuration. @@ -50,7 +47,6 @@ func defaultCallInfo(path string) callInfo { return callInfo{ contentType: "application/json", operation: path, - metatada: metadata.Metadata{}, } } @@ -69,19 +65,3 @@ func (o OperationCallOption) before(c *callInfo) error { c.operation = o.Operation return nil } - -// Metadata is Metadata call option -func Metadata(metatada metadata.Metadata) CallOption { - return MetadataCallOption{Metatada: metatada} -} - -// MetadataCallOption is set Metadata for client call -type MetadataCallOption struct { - EmptyCallOption - Metatada metadata.Metadata -} - -func (o MetadataCallOption) before(c *callInfo) error { - c.metatada = o.Metatada - return nil -} diff --git a/transport/http/client.go b/transport/http/client.go index 436859d5e..5d5a13e4d 100644 --- a/transport/http/client.go +++ b/transport/http/client.go @@ -12,7 +12,6 @@ import ( "github.com/go-kratos/kratos/v2/encoding" "github.com/go-kratos/kratos/v2/errors" "github.com/go-kratos/kratos/v2/internal/httputil" - "github.com/go-kratos/kratos/v2/metadata" "github.com/go-kratos/kratos/v2/middleware" "github.com/go-kratos/kratos/v2/registry" "github.com/go-kratos/kratos/v2/transport" @@ -197,12 +196,9 @@ func (client *Client) Invoke(ctx context.Context, method, path string, args inte if client.opts.userAgent != "" { req.Header.Set("User-Agent", client.opts.userAgent) } - if c.metatada == nil { - c.metatada = metadata.Metadata{} - } ctx = transport.NewClientContext(ctx, &Transport{ endpoint: client.opts.endpoint, - metadata: c.metatada, + header: headerCarrier(req.Header), path: path, method: method, operation: c.operation, @@ -230,11 +226,6 @@ func (client *Client) invoke(ctx context.Context, req *http.Request, args interf req.URL.Scheme = scheme req.URL.Host = addr } - if tr, ok := transport.FromClientContext(ctx); ok { - for _, key := range tr.Metadata().Keys() { - req.Header.Set(key, tr.Metadata().Get(key)) - } - } res, err := client.do(ctx, req, c) if done != nil { done(ctx, balancer.DoneInfo{Err: err}) diff --git a/transport/http/server.go b/transport/http/server.go index 12f7664ce..99266ef4f 100644 --- a/transport/http/server.go +++ b/transport/http/server.go @@ -12,7 +12,6 @@ import ( ic "github.com/go-kratos/kratos/v2/internal/context" "github.com/go-kratos/kratos/v2/internal/host" "github.com/go-kratos/kratos/v2/log" - "github.com/go-kratos/kratos/v2/metadata" "github.com/go-kratos/kratos/v2/middleware" "github.com/go-kratos/kratos/v2/transport" @@ -168,7 +167,7 @@ func (s *Server) filter() mux.MiddlewareFunc { path: req.RequestURI, method: req.Method, operation: req.RequestURI, - metadata: metadata.New(req.Header), + header: headerCarrier(req.Header), } if r := mux.CurrentRoute(req); r != nil { if path, err := r.GetPathTemplate(); err == nil { diff --git a/transport/http/transport.go b/transport/http/transport.go index 8a9eb9bbb..07a42741a 100644 --- a/transport/http/transport.go +++ b/transport/http/transport.go @@ -2,8 +2,8 @@ package http import ( "context" + "net/http" - "github.com/go-kratos/kratos/v2/metadata" "github.com/go-kratos/kratos/v2/transport" ) @@ -17,7 +17,7 @@ type Transport struct { path string method string operation string - metadata metadata.Metadata + header headerCarrier } // Kind returns the transport kind. @@ -35,21 +35,9 @@ func (tr *Transport) Operation() string { return tr.operation } -// SetOperation sets the transport operation. -func (tr *Transport) SetOperation(operation string) { - tr.operation = operation -} - -// Metadata returns the transport metadata. -func (tr *Transport) Metadata() metadata.Metadata { - return tr.metadata -} - -// WithMetadata with a metadata into transport md. -func (tr *Transport) WithMetadata(md metadata.Metadata) { - for k, v := range md { - tr.metadata.Set(k, v) - } +// Header returns the transport header. +func (tr *Transport) Header() transport.Header { + return tr.header } // Path returns the Transport path from server context. @@ -71,3 +59,33 @@ func Method(ctx context.Context) string { } return "" } + +// SetOperation sets the transport operation. +func SetOperation(ctx context.Context, op string) { + if tr, ok := transport.FromServerContext(ctx); ok { + if tr, ok := tr.(*Transport); ok { + tr.operation = op + } + } +} + +type headerCarrier http.Header + +// Get returns the value associated with the passed key. +func (hc headerCarrier) Get(key string) string { + return http.Header(hc).Get(key) +} + +// Set stores the key-value pair. +func (hc headerCarrier) Set(key string, value string) { + http.Header(hc).Set(key, value) +} + +// Keys lists the keys stored in this carrier. +func (hc headerCarrier) Keys() []string { + keys := make([]string, 0, len(hc)) + for k := range http.Header(hc) { + keys = append(keys, k) + } + return keys +} diff --git a/transport/transport.go b/transport/transport.go index 3d3ac1137..fa814d5f0 100644 --- a/transport/transport.go +++ b/transport/transport.go @@ -9,7 +9,6 @@ import ( _ "github.com/go-kratos/kratos/v2/encoding/proto" _ "github.com/go-kratos/kratos/v2/encoding/xml" _ "github.com/go-kratos/kratos/v2/encoding/yaml" - "github.com/go-kratos/kratos/v2/metadata" ) // Server is transport server. @@ -23,18 +22,19 @@ type Endpointer interface { Endpoint() (*url.URL, error) } +// Header is the storage medium used by a Header. +type Header interface { + Get(key string) string + Set(key string, value string) + Keys() []string +} + // Transporter is transport context value interface. type Transporter interface { Kind() string Endpoint() string - Operation() string - SetOperation(string) - - Metadata() metadata.Metadata - // WithMetadata merge new metadata into transport, - // it will override old metadata key value if key exists - WithMetadata(metadata.Metadata) + Header() Header } type serverTransportKey struct{} @@ -61,26 +61,3 @@ func FromClientContext(ctx context.Context) (tr Transporter, ok bool) { tr, ok = ctx.Value(clientTransportKey{}).(Transporter) return } - -// SetOperation set operation into context transport. -func SetOperation(ctx context.Context, method string) { - if tr, ok := FromServerContext(ctx); ok { - tr.SetOperation(method) - } -} - -// Operation returns the Transport operation from server context. -func Operation(ctx context.Context) string { - if tr, ok := FromServerContext(ctx); ok { - return tr.Operation() - } - return "" -} - -// Metadata returns incoming metadata from server transport. -func Metadata(ctx context.Context) metadata.Metadata { - if tr, ok := FromServerContext(ctx); ok { - return tr.Metadata() - } - return metadata.Metadata{} -}