Repository: go-kratos/kratos
Pull request #1037 (2021-06-12 13:56:51)

transport/http: add vars to http context


Patch:
diff --git a/api/metadata/metadata_http.pb.go b/api/metadata/metadata_http.pb.go
index 1005cd50..42758a51 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 3cdca5a1..e928643f 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 6b781d15..0a9b475c 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 93e2c771..0fa52059 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 bd368ad6..ef919210 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 0575be1c..dce1ed2c 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 90aeeb22..06ee59a1 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 200076fe..d43d093e 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/transport/http/binding/bind.go b/transport/http/binding/bind.go
index b16148da..d45a9581 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 744a7c97..55563c0b 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 6f74960a..b70e3903 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


Test patch:
diff --git a/internal/testproto/echo_service_http.pb.go b/internal/testproto/echo_service_http.pb.go
index d4162362..7e56bd5f 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")