From eca0f35cb508b28a1d56e53df00e11c3063e32e6 Mon Sep 17 00:00:00 2001 From: Tony Chen Date: Sat, 12 Jun 2021 22:21:54 +0800 Subject: [PATCH] transport/http: add vars to http context (#1037) * add vars to http context * add query to http context * remove http deps * clean request decoder --- api/metadata/metadata_http.pb.go | 6 ++---- cmd/protoc-gen-go-http/http.go | 6 ++---- cmd/protoc-gen-go-http/template.go | 2 +- examples/blog/api/blog/v1/blog_http.pb.go | 10 ++++------ .../helloworld/helloworld/helloworld_http.pb.go | 6 ++---- examples/http/middlewares/handlers.go | 3 +-- examples/traces/api/message/message_http.pb.go | 6 ++---- examples/traces/api/user/user_http.pb.go | 6 ++---- internal/testproto/echo_service_http.pb.go | 16 +++++++--------- transport/http/binding/bind.go | 17 +++++++++-------- transport/http/codec.go | 11 +++++------ transport/http/context.go | 13 ++++++++++++- 12 files changed, 49 insertions(+), 53 deletions(-) diff --git a/api/metadata/metadata_http.pb.go b/api/metadata/metadata_http.pb.go index 1005cd506..42758a51f 100644 --- a/api/metadata/metadata_http.pb.go +++ b/api/metadata/metadata_http.pb.go @@ -6,7 +6,6 @@ package metadata import ( context "context" - middleware "github.com/go-kratos/kratos/v2/middleware" 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" @@ -15,9 +14,8 @@ 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(middleware.Middleware) var _ = new(transport.Transporter) -var _ = binding.BindVars +var _ = binding.EncodeVars const _ = http.SupportPackageIsVersion1 @@ -57,7 +55,7 @@ func _Metadata_GetServiceDesc0_HTTP_Handler(srv MetadataHTTPServer) func(ctx htt if err := ctx.Bind(&in); err != nil { return err } - if err := binding.BindVars(ctx.Vars(), &in); err != nil { + if err := ctx.BindVars(&in); err != nil { return err } transport.SetOperation(ctx, "/kratos.api.Metadata/GetServiceDesc") diff --git a/cmd/protoc-gen-go-http/http.go b/cmd/protoc-gen-go-http/http.go index 3cdca5a17..e928643fe 100644 --- a/cmd/protoc-gen-go-http/http.go +++ b/cmd/protoc-gen-go-http/http.go @@ -12,10 +12,9 @@ import ( const ( contextPackage = protogen.GoImportPath("context") - middlewarePackage = protogen.GoImportPath("github.com/go-kratos/kratos/v2/middleware") + 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") - transportPackage = protogen.GoImportPath("github.com/go-kratos/kratos/v2/transport") ) var methodSets = make(map[string]int) @@ -45,9 +44,8 @@ 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(", middlewarePackage.Ident("Middleware"), ")") g.P("var _ = new(", transportPackage.Ident("Transporter"), ")") - g.P("var _ = ", bindingPackage.Ident("BindVars")) + g.P("var _ = ", bindingPackage.Ident("EncodeVars")) 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 6b781d15f..0a9b475cd 100644 --- a/cmd/protoc-gen-go-http/template.go +++ b/cmd/protoc-gen-go-http/template.go @@ -30,7 +30,7 @@ func _{{$svrType}}_{{.Name}}{{.Num}}_HTTP_Handler(srv {{$svrType}}HTTPServer) fu return err } {{- if ne (len .Vars) 0}} - if err := binding.BindVars(ctx.Vars(), &in); err != nil { + if err := ctx.BindVars(&in); err != nil { return err } {{- end}} diff --git a/examples/blog/api/blog/v1/blog_http.pb.go b/examples/blog/api/blog/v1/blog_http.pb.go index 93e2c7718..0fa52059e 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" - middleware "github.com/go-kratos/kratos/v2/middleware" 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" @@ -15,9 +14,8 @@ 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(middleware.Middleware) var _ = new(transport.Transporter) -var _ = binding.BindVars +var _ = binding.EncodeVars const _ = http.SupportPackageIsVersion1 @@ -63,7 +61,7 @@ func _BlogService_UpdateArticle0_HTTP_Handler(srv BlogServiceHTTPServer) func(ct if err := ctx.Bind(&in); err != nil { return err } - if err := binding.BindVars(ctx.Vars(), &in); err != nil { + if err := ctx.BindVars(&in); err != nil { return err } transport.SetOperation(ctx, "/blog.api.v1.BlogService/UpdateArticle") @@ -85,7 +83,7 @@ func _BlogService_DeleteArticle0_HTTP_Handler(srv BlogServiceHTTPServer) func(ct if err := ctx.Bind(&in); err != nil { return err } - if err := binding.BindVars(ctx.Vars(), &in); err != nil { + if err := ctx.BindVars(&in); err != nil { return err } transport.SetOperation(ctx, "/blog.api.v1.BlogService/DeleteArticle") @@ -107,7 +105,7 @@ func _BlogService_GetArticle0_HTTP_Handler(srv BlogServiceHTTPServer) func(ctx h if err := ctx.Bind(&in); err != nil { return err } - if err := binding.BindVars(ctx.Vars(), &in); err != nil { + if err := ctx.BindVars(&in); err != nil { return err } transport.SetOperation(ctx, "/blog.api.v1.BlogService/GetArticle") diff --git a/examples/helloworld/helloworld/helloworld_http.pb.go b/examples/helloworld/helloworld/helloworld_http.pb.go index bd368ad60..ef9192108 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" - middleware "github.com/go-kratos/kratos/v2/middleware" 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" @@ -15,9 +14,8 @@ 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(middleware.Middleware) var _ = new(transport.Transporter) -var _ = binding.BindVars +var _ = binding.EncodeVars const _ = http.SupportPackageIsVersion1 @@ -36,7 +34,7 @@ func _Greeter_SayHello0_HTTP_Handler(srv GreeterHTTPServer) func(ctx http.Contex if err := ctx.Bind(&in); err != nil { return err } - if err := binding.BindVars(ctx.Vars(), &in); err != nil { + if err := ctx.BindVars(&in); err != nil { return err } transport.SetOperation(ctx, "/helloworld.Greeter/SayHello") diff --git a/examples/http/middlewares/handlers.go b/examples/http/middlewares/handlers.go index 0575be1c0..dce1ed2cf 100644 --- a/examples/http/middlewares/handlers.go +++ b/examples/http/middlewares/handlers.go @@ -6,7 +6,6 @@ import ( "github.com/go-kratos/kratos/examples/helloworld/helloworld" "github.com/go-kratos/kratos/v2/transport" "github.com/go-kratos/kratos/v2/transport/http" - "github.com/go-kratos/kratos/v2/transport/http/binding" ) func sayHelloHandler(ctx http.Context) error { @@ -16,7 +15,7 @@ func sayHelloHandler(ctx http.Context) error { } // binding /hello/{name} to in.Name - if err := binding.BindVars(ctx.Vars(), &in); err != nil { + if err := ctx.BindVars(&in); err != nil { return err } diff --git a/examples/traces/api/message/message_http.pb.go b/examples/traces/api/message/message_http.pb.go index 90aeeb22e..06ee59a1c 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" - middleware "github.com/go-kratos/kratos/v2/middleware" 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" @@ -15,9 +14,8 @@ 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(middleware.Middleware) var _ = new(transport.Transporter) -var _ = binding.BindVars +var _ = binding.EncodeVars const _ = http.SupportPackageIsVersion1 @@ -36,7 +34,7 @@ func _MessageService_GetUserMessage0_HTTP_Handler(srv MessageServiceHTTPServer) if err := ctx.Bind(&in); err != nil { return err } - if err := binding.BindVars(ctx.Vars(), &in); err != nil { + if err := ctx.BindVars(&in); err != nil { return err } transport.SetOperation(ctx, "/api.message.v1.MessageService/GetUserMessage") diff --git a/examples/traces/api/user/user_http.pb.go b/examples/traces/api/user/user_http.pb.go index 200076fe1..d43d093ec 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" - middleware "github.com/go-kratos/kratos/v2/middleware" 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" @@ -15,9 +14,8 @@ 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(middleware.Middleware) var _ = new(transport.Transporter) -var _ = binding.BindVars +var _ = binding.EncodeVars const _ = http.SupportPackageIsVersion1 @@ -36,7 +34,7 @@ func _User_GetMyMessages0_HTTP_Handler(srv UserHTTPServer) func(ctx http.Context if err := ctx.Bind(&in); err != nil { return err } - if err := binding.BindVars(ctx.Vars(), &in); err != nil { + if err := ctx.BindVars(&in); err != nil { return err } transport.SetOperation(ctx, "/api.user.v1.User/GetMyMessages") diff --git a/internal/testproto/echo_service_http.pb.go b/internal/testproto/echo_service_http.pb.go index d4162362a..7e56bd5fb 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" - middleware "github.com/go-kratos/kratos/v2/middleware" 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" @@ -15,9 +14,8 @@ 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(middleware.Middleware) var _ = new(transport.Transporter) -var _ = binding.BindVars +var _ = binding.EncodeVars const _ = http.SupportPackageIsVersion1 @@ -48,7 +46,7 @@ func _EchoService_Echo0_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Co if err := ctx.Bind(&in); err != nil { return err } - if err := binding.BindVars(ctx.Vars(), &in); err != nil { + if err := ctx.BindVars(&in); err != nil { return err } transport.SetOperation(ctx, "/testproto.EchoService/Echo") @@ -70,7 +68,7 @@ func _EchoService_Echo1_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Co if err := ctx.Bind(&in); err != nil { return err } - if err := binding.BindVars(ctx.Vars(), &in); err != nil { + if err := ctx.BindVars(&in); err != nil { return err } transport.SetOperation(ctx, "/testproto.EchoService/Echo") @@ -92,7 +90,7 @@ func _EchoService_Echo2_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Co if err := ctx.Bind(&in); err != nil { return err } - if err := binding.BindVars(ctx.Vars(), &in); err != nil { + if err := ctx.BindVars(&in); err != nil { return err } transport.SetOperation(ctx, "/testproto.EchoService/Echo") @@ -114,7 +112,7 @@ func _EchoService_Echo3_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Co if err := ctx.Bind(&in); err != nil { return err } - if err := binding.BindVars(ctx.Vars(), &in); err != nil { + if err := ctx.BindVars(&in); err != nil { return err } transport.SetOperation(ctx, "/testproto.EchoService/Echo") @@ -136,7 +134,7 @@ func _EchoService_Echo4_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Co if err := ctx.Bind(&in); err != nil { return err } - if err := binding.BindVars(ctx.Vars(), &in); err != nil { + if err := ctx.BindVars(&in); err != nil { return err } transport.SetOperation(ctx, "/testproto.EchoService/Echo") @@ -196,7 +194,7 @@ func _EchoService_EchoDelete0_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx h if err := ctx.Bind(&in); err != nil { return err } - if err := binding.BindVars(ctx.Vars(), &in); err != nil { + if err := ctx.BindVars(&in); err != nil { return err } transport.SetOperation(ctx, "/testproto.EchoService/EchoDelete") diff --git a/transport/http/binding/bind.go b/transport/http/binding/bind.go index b16148dad..d45a95812 100644 --- a/transport/http/binding/bind.go +++ b/transport/http/binding/bind.go @@ -2,10 +2,19 @@ package binding import ( "net/http" + "net/url" "google.golang.org/protobuf/proto" ) +// BindQuery bind vars parameters to target. +func BindQuery(vars url.Values, target interface{}) error { + if msg, ok := target.(proto.Message); ok { + return mapProto(msg, vars) + } + return mapForm(target, vars) +} + // BindForm bind form parameters to target. func BindForm(req *http.Request, target interface{}) error { if err := req.ParseForm(); err != nil { @@ -16,11 +25,3 @@ func BindForm(req *http.Request, target interface{}) error { } return mapForm(target, req.Form) } - -// BindVars bind map parameters to target. -func BindVars(values map[string][]string, target interface{}) error { - if msg, ok := target.(proto.Message); ok { - return mapProto(msg, values) - } - return mapForm(target, values) -} diff --git a/transport/http/codec.go b/transport/http/codec.go index 744a7c977..55563c0b9 100644 --- a/transport/http/codec.go +++ b/transport/http/codec.go @@ -24,8 +24,7 @@ type EncodeErrorFunc func(http.ResponseWriter, *http.Request, error) // DefaultRequestDecoder decodes the request body to object. func DefaultRequestDecoder(r *http.Request, v interface{}) error { - codec, ok := CodecForRequest(r, "Content-Type") - if ok { + if codec, ok := CodecForRequest(r, "Content-Type"); ok { data, err := ioutil.ReadAll(r.Body) if err != nil { return errors.BadRequest("CODEC", err.Error()) @@ -33,10 +32,10 @@ func DefaultRequestDecoder(r *http.Request, v interface{}) error { if err := codec.Unmarshal(data, v); err != nil { return errors.BadRequest("CODEC", err.Error()) } - } else { - if err := binding.BindForm(r, v); err != nil { - return errors.BadRequest("CODEC", err.Error()) - } + return nil + } + if err := binding.BindForm(r, v); err != nil { + return errors.BadRequest("CODEC", err.Error()) } return nil } diff --git a/transport/http/context.go b/transport/http/context.go index 6f74960ab..b70e39035 100644 --- a/transport/http/context.go +++ b/transport/http/context.go @@ -10,6 +10,7 @@ import ( "time" "github.com/go-kratos/kratos/v2/middleware" + "github.com/go-kratos/kratos/v2/transport/http/binding" "github.com/gorilla/mux" ) @@ -22,12 +23,16 @@ type HandlerFunc func(Context) error type Context interface { context.Context Vars() url.Values + Query() url.Values Form() url.Values Header() http.Header Request() *http.Request Response() http.ResponseWriter Middleware(middleware.Handler) middleware.Handler Bind(interface{}) error + BindVars(interface{}) error + BindQuery(interface{}) error + BindForm(interface{}) error Returns(interface{}, error) error Result(int, interface{}) error JSON(int, interface{}) error @@ -62,12 +67,18 @@ func (c *wrapper) Form() url.Values { } return c.req.Form } +func (c *wrapper) Query() url.Values { + return c.req.URL.Query() +} func (c *wrapper) Request() *http.Request { return c.req } func (c *wrapper) Response() http.ResponseWriter { return c.res } func (c *wrapper) Middleware(h middleware.Handler) middleware.Handler { return middleware.Chain(c.route.srv.ms...)(h) } -func (c *wrapper) Bind(v interface{}) error { return c.route.srv.dec(c.req, v) } +func (c *wrapper) Bind(v interface{}) error { return c.route.srv.dec(c.req, v) } +func (c *wrapper) BindVars(v interface{}) error { return binding.BindQuery(c.Vars(), v) } +func (c *wrapper) BindQuery(v interface{}) error { return binding.BindQuery(c.Query(), v) } +func (c *wrapper) BindForm(v interface{}) error { return binding.BindForm(c.req, v) } func (c *wrapper) Returns(v interface{}, err error) error { if err != nil { return err