Middleware/metadata v2 (#1050)

* add middleware metadata
* add transport header
* add transport carrier

Co-authored-by: longXboy <longxboy@gmail.com>
pull/1054/head
Tony Chen 4 years ago committed by GitHub
parent 7f2e3becbe
commit 8d8cd8c8a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      api/metadata/metadata_http.pb.go
  2. 2
      cmd/protoc-gen-go-http/http.go
  3. 2
      cmd/protoc-gen-go-http/template.go
  4. 12
      examples/blog/api/blog/v1/blog_http.pb.go
  5. 4
      examples/helloworld/helloworld/helloworld_http.pb.go
  6. 3
      examples/http/middlewares/handlers.go
  7. 22
      examples/metadata/client/main.go
  8. 12
      examples/metadata/server/main.go
  9. 4
      examples/traces/api/message/message_http.pb.go
  10. 4
      examples/traces/api/user/user_http.pb.go
  11. 20
      internal/testproto/echo_service_http.pb.go
  12. 40
      internal/testproto/echo_service_test.go
  13. 46
      metadata/context.go
  14. 26
      metadata/metadata.go
  15. 11
      middleware/logging/logging_test.go
  16. 95
      middleware/metadata/metadata.go
  17. 4
      middleware/tracing/tracing.go
  18. 10
      transport/grpc/client.go
  19. 3
      transport/grpc/server.go
  20. 37
      transport/grpc/transport.go
  21. 20
      transport/http/calloption.go
  22. 11
      transport/http/client.go
  23. 3
      transport/http/server.go
  24. 52
      transport/http/transport.go
  25. 39
      transport/transport.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))
})

@ -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()

@ -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}}))
})

@ -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))
})

@ -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))
})

@ -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
})

@ -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)

@ -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(),
),
)

@ -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))
})

@ -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))
})

@ -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))
})

@ -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)
}

@ -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)
}

@ -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 _, m := range mds {
for k, v := range m {
if k == "" {
continue
}
key := strings.ToLower(k)
if len(v) > 0 && v[0] != "" {
md[key] = v[0]
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{}

@ -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)

@ -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)
}
}
}

@ -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)

@ -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...)
}

@ -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

@ -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
}

@ -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
}

@ -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})

@ -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 {

@ -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
}

@ -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{}
}

Loading…
Cancel
Save