Repository: go-kratos/kratos
Pull request #1050 (2021-06-13 13:59:53)

Middleware/metadata v2


Patch:
diff --git a/api/metadata/metadata_http.pb.go b/api/metadata/metadata_http.pb.go
index 09c21cf1..8485c35b 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 d4d3288f..0b18a29a 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 42551999..4a313099 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 4aef7f9e..3fcd414d 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 e20130e3..55517338 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 dce1ed2c..08950ece 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 2499c432..d3248b81 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 67e35e0a..e7cab1c4 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 40ad223d..bfa19083 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 cf26c3f2..758b4560 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/metadata/context.go b/metadata/context.go
new file mode 100644
index 00000000..e05a3775
--- /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 445886fb..7cc225f2 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/metadata/metadata.go b/middleware/metadata/metadata.go
new file mode 100644
index 00000000..ac1e76ed
--- /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 2b3f385d..bc5e70db 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 55d6e7f2..58cbe950 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 e6c6bf3a..5710c824 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 89bed23b..80814f58 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
+
+// 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)
 }
 
-// WithMetadata with a metadata into transport md.
-func (tr *Transport) WithMetadata(md metadata.Metadata) {
-	for k, v := range md {
-		tr.metadata.Set(k, v)
+// 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 b2f6b043..cd2cd72c 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 436859d5..5d5a13e4 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 12f7664c..99266ef4 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 8a9eb9bb..07a42741 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 3d3ac113..fa814d5f 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{}
-}


Test patch:
diff --git a/internal/testproto/echo_service_http.pb.go b/internal/testproto/echo_service_http.pb.go
index feca7ea2..819db2c8 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 3621cfc3..373c7619 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/middleware/logging/logging_test.go b/middleware/logging/logging_test.go
index 104c6570..e08d9db5 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)