Repository: go-kratos/kratos
Pull request #1158 (2021-07-06 13:38:23)

add form for codec


Patch:
diff --git a/README.md b/README.md
index 040696fb..6163f155 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,8 @@ Kratos is a microservice-oriented governance framework implements by golang, whi
 - Multiple data sources are supported for [configurations](https://go-kratos.dev/en/docs/component/config) and dynamic configurations (use atomic operations).
 - In the protocol of HTTP/gRPC, use uniform [metadata](https://go-kratos.dev/en/docs/component/metadata) transfer method.
 - You can define [errors](https://go-kratos.dev/en/docs/component/errors/) in protos and generate enums with protoc-gen-go.
+- You can define [verification rules]([examples/validate](https://go-kratos.dev/docs/component/middleware/validate)) in Protobuf which is supported by HTTP/gRPC service.
+- [Swagger API](https://go-kratos.dev/docs/guide/openapi) generated Automatically and embed Swagger UI endpoint can be started by adding [Swagger plugin](https://github.com/go-kratos/swagger-api).
 
 Kratos is accessible, powerful, and provides tools required for large, robust applications.
 
diff --git a/config/reader.go b/config/reader.go
index eb42fe8e..71806a3c 100644
--- a/config/reader.go
+++ b/config/reader.go
@@ -48,29 +48,7 @@ func (r *reader) Merge(kvs ...*KeyValue) error {
 }
 
 func (r *reader) Value(path string) (Value, bool) {
-	var (
-		next = r.values
-		keys = strings.Split(path, ".")
-		last = len(keys) - 1
-	)
-	for idx, key := range keys {
-		value, ok := next[key]
-		if !ok {
-			return nil, false
-		}
-		if idx == last {
-			av := &atomicValue{}
-			av.Store(value)
-			return av, true
-		}
-		switch vm := value.(type) {
-		case map[string]interface{}:
-			next = vm
-		default:
-			return nil, false
-		}
-	}
-	return nil, false
+	return readValue(r.values, path)
 }
 
 func (r *reader) Source() ([]byte, error) {
@@ -114,6 +92,34 @@ func convertMap(src interface{}) interface{} {
 	}
 }
 
+// readValue read Value in given map[string]interface{}
+// by the given path, will return false if not found.
+func readValue(values map[string]interface{}, path string) (Value, bool) {
+	var (
+		next = values
+		keys = strings.Split(path, ".")
+		last = len(keys) - 1
+	)
+	for idx, key := range keys {
+		value, ok := next[key]
+		if !ok {
+			return nil, false
+		}
+		if idx == last {
+			av := &atomicValue{}
+			av.Store(value)
+			return av, true
+		}
+		switch vm := value.(type) {
+		case map[string]interface{}:
+			next = vm
+		default:
+			return nil, false
+		}
+	}
+	return nil, false
+}
+
 func marshalJSON(v interface{}) ([]byte, error) {
 	if m, ok := v.(proto.Message); ok {
 		return protojson.MarshalOptions{EmitUnpopulated: true}.Marshal(m)
diff --git a/encoding/form/form.go b/encoding/form/form.go
index 9b6696fc..b84aa481 100644
--- a/encoding/form/form.go
+++ b/encoding/form/form.go
@@ -1,30 +1,49 @@
 package form
 
 import (
-	"github.com/go-kratos/kratos/v2/encoding"
-	"github.com/gorilla/schema"
 	"net/url"
+	"reflect"
+
+	"github.com/go-kratos/kratos/v2/encoding"
+
+	"github.com/go-playground/form/v4"
+	"google.golang.org/protobuf/proto"
 )
 
+// Name is form codec name
 const Name = "x-www-form-urlencoded"
 
 func init() {
-	decoder := schema.NewDecoder()
-	decoder.SetAliasTag("json")
-	encoder := schema.NewEncoder()
-	encoder.SetAliasTag("json")
+	decoder := form.NewDecoder()
+	decoder.SetTagName("json")
+	encoder := form.NewEncoder()
+	encoder.SetTagName("json")
 	encoding.RegisterCodec(codec{encoder: encoder, decoder: decoder})
 }
 
 type codec struct {
-	encoder *schema.Encoder
-	decoder *schema.Decoder
+	encoder *form.Encoder
+	decoder *form.Decoder
 }
 
 func (c codec) Marshal(v interface{}) ([]byte, error) {
-	var vs = url.Values{}
-	if err := c.encoder.Encode(v, vs); err != nil {
-		return nil, err
+	var vs url.Values
+	var err error
+	if m, ok := v.(proto.Message); ok {
+		vs, err = EncodeMap(m)
+		if err != nil {
+			return nil, err
+		}
+	} else {
+		vs, err = c.encoder.Encode(v)
+		if err != nil {
+			return nil, err
+		}
+	}
+	for k, v := range vs {
+		if len(v) == 0 {
+			delete(vs, k)
+		}
 	}
 	return []byte(vs.Encode()), nil
 }
@@ -34,6 +53,20 @@ func (c codec) Unmarshal(data []byte, v interface{}) error {
 	if err != nil {
 		return err
 	}
+
+	rv := reflect.ValueOf(v)
+	for rv.Kind() == reflect.Ptr {
+		if rv.IsNil() {
+			rv.Set(reflect.New(rv.Type().Elem()))
+		}
+		rv = rv.Elem()
+	}
+	if m, ok := v.(proto.Message); ok {
+		return MapProto(m, vs)
+	} else if m, ok := reflect.Indirect(reflect.ValueOf(v)).Interface().(proto.Message); ok {
+		return MapProto(m, vs)
+	}
+
 	if err := c.decoder.Decode(v, vs); err != nil {
 		return err
 	}
diff --git a/transport/http/binding/proto.go b/encoding/form/proto_decode.go
similarity index 99%
rename from transport/http/binding/proto.go
rename to encoding/form/proto_decode.go
index 6425600e..0a817b30 100644
--- a/transport/http/binding/proto.go
+++ b/encoding/form/proto_decode.go
@@ -1,4 +1,4 @@
-package binding
+package form
 
 import (
 	"encoding/base64"
@@ -17,7 +17,7 @@ import (
 	"google.golang.org/protobuf/types/known/wrapperspb"
 )
 
-func mapProto(msg proto.Message, values map[string][]string) error {
+func MapProto(msg proto.Message, values map[string][]string) error {
 	for key, values := range values {
 		if err := populateFieldValues(msg.ProtoReflect(), strings.Split(key, "."), values); err != nil {
 			return err
diff --git a/encoding/form/proto_encode.go b/encoding/form/proto_encode.go
new file mode 100644
index 00000000..45a5f08f
--- /dev/null
+++ b/encoding/form/proto_encode.go
@@ -0,0 +1,187 @@
+package form
+
+import (
+	"encoding/base64"
+	"fmt"
+	"net/url"
+	"reflect"
+	"strconv"
+	"strings"
+	"time"
+
+	"google.golang.org/genproto/protobuf/field_mask"
+	"google.golang.org/protobuf/proto"
+	"google.golang.org/protobuf/reflect/protoreflect"
+	"google.golang.org/protobuf/types/known/durationpb"
+	"google.golang.org/protobuf/types/known/timestamppb"
+	"google.golang.org/protobuf/types/known/wrapperspb"
+)
+
+// EncodeMap encode proto message to url query.
+func EncodeMap(msg proto.Message) (url.Values, error) {
+	if msg == nil || (reflect.ValueOf(msg).Kind() == reflect.Ptr && reflect.ValueOf(msg).IsNil()) {
+		return url.Values{}, nil
+	}
+	u := make(url.Values)
+	err := encodeByField(u, "", msg.ProtoReflect())
+	if err != nil {
+		return nil, err
+	}
+	return u, nil
+}
+
+func encodeByField(u url.Values, path string, v protoreflect.Message) error {
+	for i := 0; i < v.Descriptor().Fields().Len(); i++ {
+		fd := v.Descriptor().Fields().Get(i)
+		var key string
+		var newPath string
+		if fd.HasJSONName() {
+			key = fd.JSONName()
+		} else {
+			key = fd.TextName()
+		}
+		if path == "" {
+			newPath = key
+		} else {
+			newPath = path + "." + key
+		}
+
+		if of := fd.ContainingOneof(); of != nil {
+			if f := v.WhichOneof(of); f != nil {
+				if f != fd {
+					continue
+				}
+			}
+			continue
+		}
+		switch {
+		case fd.IsList():
+			if v.Get(fd).List().Len() > 0 {
+				list, err := encodeRepeatedField(fd, v.Get(fd).List())
+				if err != nil {
+					return err
+				}
+				u[newPath] = list
+			}
+		case fd.IsMap():
+			if v.Get(fd).Map().Len() > 0 {
+				m, err := encodeMapField(fd, v.Get(fd).Map())
+				if err != nil {
+					return err
+				}
+				for k, value := range m {
+					u[fmt.Sprintf("%s[%s]", newPath, k)] = []string{value}
+				}
+			}
+		case (fd.Kind() == protoreflect.MessageKind) || (fd.Kind() == protoreflect.GroupKind):
+			value, err := encodeMessage(fd.Message(), v.Get(fd))
+			if err == nil {
+				u[newPath] = []string{value}
+				continue
+			}
+			err = encodeByField(u, newPath, v.Get(fd).Message())
+			if err != nil {
+				return err
+			}
+		default:
+			value, err := encodeField(fd, v.Get(fd))
+			if err != nil {
+				return err
+			}
+			u[newPath] = []string{value}
+		}
+	}
+
+	return nil
+}
+
+func encodeRepeatedField(fieldDescriptor protoreflect.FieldDescriptor, list protoreflect.List) ([]string, error) {
+	var values []string
+	for i := 0; i < list.Len(); i++ {
+		value, err := encodeField(fieldDescriptor, list.Get(i))
+		if err != nil {
+			return nil, err
+		}
+		values = append(values, value)
+	}
+
+	return values, nil
+}
+
+func encodeMapField(fieldDescriptor protoreflect.FieldDescriptor, mp protoreflect.Map) (map[string]string, error) {
+	m := make(map[string]string)
+	mp.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
+		key, err := encodeField(fieldDescriptor.MapValue(), k.Value())
+		if err != nil {
+			return false
+		}
+		value, err := encodeField(fieldDescriptor.MapValue(), v)
+		if err != nil {
+			return false
+		}
+		m[key] = value
+		return true
+	})
+
+	return m, nil
+}
+
+func encodeField(fieldDescriptor protoreflect.FieldDescriptor, value protoreflect.Value) (string, error) {
+	switch fieldDescriptor.Kind() {
+	case protoreflect.BoolKind:
+		return strconv.FormatBool(value.Bool()), nil
+	case protoreflect.EnumKind:
+		if fieldDescriptor.Enum().FullName() == "google.protobuf.NullValue" {
+			return "null", nil
+		}
+		desc := fieldDescriptor.Enum().Values().ByNumber(value.Enum())
+		return string(desc.Name()), nil
+	case protoreflect.StringKind:
+		return value.String(), nil
+	case protoreflect.BytesKind:
+		return base64.URLEncoding.EncodeToString(value.Bytes()), nil
+	case protoreflect.MessageKind, protoreflect.GroupKind:
+		return encodeMessage(fieldDescriptor.Message(), value)
+	default:
+		return fmt.Sprintf("%v", value.Interface()), nil
+	}
+}
+
+// marshalMessage marshals the fields in the given protoreflect.Message.
+// If the typeURL is non-empty, then a synthetic "@type" field is injected
+// containing the URL as the value.
+func encodeMessage(msgDescriptor protoreflect.MessageDescriptor, value protoreflect.Value) (string, error) {
+	switch msgDescriptor.FullName() {
+	case "google.protobuf.Timestamp":
+		t, ok := value.Interface().(*timestamppb.Timestamp)
+		if !ok {
+			return "", nil
+		}
+		return t.AsTime().Format(time.RFC3339Nano), nil
+	case "google.protobuf.Duration":
+		d, ok := value.Interface().(*durationpb.Duration)
+		if !ok {
+			return "", nil
+		}
+		return d.AsDuration().String(), nil
+	case "google.protobuf.BytesValue":
+		b, ok := value.Interface().(*wrapperspb.BytesValue)
+		if !ok {
+			return "", nil
+		}
+		return base64.StdEncoding.EncodeToString(b.Value), nil
+	case "google.protobuf.DoubleValue", "google.protobuf.FloatValue", "google.protobuf.Int64Value", "google.protobuf.Int32Value",
+		"google.protobuf.UInt64Value", "google.protobuf.UInt32Value", "google.protobuf.BoolValue", "google.protobuf.StringValue":
+		fd := msgDescriptor.Fields()
+		v := value.Message().Get(fd.ByName(protoreflect.Name("value"))).Message()
+		return fmt.Sprintf("%v", v.Interface()), nil
+	case "google.protobuf.FieldMask":
+		m, ok := value.Interface().(*field_mask.FieldMask)
+		if !ok {
+			return "", nil
+		}
+		return strings.Join(m.Paths, ","), nil
+	default:
+		return "", fmt.Errorf("unsupported message type: %q", string(msgDescriptor.FullName()))
+	}
+}
diff --git a/examples/README.md b/examples/README.md
index 87458e3a..458059d2 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -12,3 +12,4 @@
 - examples/traces is middleware/tracing example，middleware/tracing is implemented by opentelemetry.
 - examples/validate is middleware/validate example, the verification code is generated by proto-gen-validate.
 - examples/ws is implementation of transport interface with websocket example.
+- examples/swagger is implementation of server with embed swagger api.
diff --git a/examples/go.mod b/examples/go.mod
index 1a260a44..93ee15a4 100644
--- a/examples/go.mod
+++ b/examples/go.mod
@@ -14,9 +14,10 @@ require (
 	github.com/go-errors/errors v1.4.0 // indirect
 	github.com/go-kratos/consul v0.1.0
 	github.com/go-kratos/etcd v0.1.0
-	github.com/go-kratos/kratos/v2 v2.0.0-rc6
+	github.com/go-kratos/kratos/v2 v2.0.0-rc7
 	github.com/go-kratos/nacos v0.1.0
 	github.com/go-kratos/prometheus v0.0.0-20210522055322-137e29e7cf47
+	github.com/go-kratos/swagger-api v0.1.8
 	github.com/go-playground/validator/v10 v10.6.1 // indirect
 	github.com/go-redis/redis/extra/redisotel v0.3.0
 	github.com/go-redis/redis/v8 v8.9.0
@@ -24,7 +25,6 @@ require (
 	github.com/google/wire v0.5.0
 	github.com/gorilla/handlers v1.5.1
 	github.com/gorilla/mux v1.8.0
-	github.com/gorilla/schema v1.2.0 // indirect
 	github.com/gorilla/websocket v1.4.2
 	github.com/hashicorp/consul/api v1.8.1
 	github.com/hashicorp/go-hclog v0.16.1 // indirect
@@ -34,6 +34,7 @@ require (
 	github.com/kr/text v0.2.0 // indirect
 	github.com/labstack/echo/v4 v4.3.0
 	github.com/leodido/go-urn v1.2.1 // indirect
+	github.com/longXboy/grpc-gateway/v2 v2.0.0-20210707031540-bd2d73d86cee
 	github.com/mattn/go-isatty v0.0.13 // indirect
 	github.com/nacos-group/nacos-sdk-go v1.0.7
 	github.com/prometheus/client_golang v1.9.0
@@ -49,7 +50,7 @@ require (
 	go.uber.org/multierr v1.7.0 // indirect
 	go.uber.org/zap v1.18.1
 	golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect
-	google.golang.org/genproto v0.0.0-20210629200056-84d6f6074151
+	google.golang.org/genproto v0.0.0-20210701191553-46259e63a0a9
 	google.golang.org/grpc v1.39.0
 	google.golang.org/protobuf v1.27.1
 	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
diff --git a/examples/go.sum b/examples/go.sum
index 9a0582a6..decab7d2 100644
--- a/examples/go.sum
+++ b/examples/go.sum
@@ -5,11 +5,32 @@ cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6A
 cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
 cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
 cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
 cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
 cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
 cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
 cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 entgo.io/ent v0.8.0 h1:xirrW//1oda7pp0bz+XssSOv4/C3nmgYQOxjIfljFt8=
 entgo.io/ent v0.8.0/go.mod h1:KNjsukat/NJi6zJh1utwRadsbGOZsBbAZNDxkW7tMCc=
@@ -64,6 +85,9 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
 github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
 github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
@@ -129,6 +153,7 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
 github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
@@ -139,6 +164,8 @@ github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm
 github.com/go-errors/errors v1.4.0 h1:2OA7MFw38+e9na72T1xgkomPb6GzZzzxvJ5U630FoRM=
 github.com/go-errors/errors v1.4.0/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
@@ -150,12 +177,16 @@ github.com/go-kratos/nacos v0.1.0 h1:sUvTsgZ4u88YaKF/jAi2Rdr+hzPCfQtmNjBpiyEbbJ0
 github.com/go-kratos/nacos v0.1.0/go.mod h1:qhVsyp6RyDDEKLtT0/iTMaN3D7SheRMrYb2bV0jYqjw=
 github.com/go-kratos/prometheus v0.0.0-20210522055322-137e29e7cf47 h1:uJennLdg0rwhrIl0bjsObwub+I3U0vJGAhpK6CYASrM=
 github.com/go-kratos/prometheus v0.0.0-20210522055322-137e29e7cf47/go.mod h1:e3D0pnFDX5SG+ZGmGONd83WvrbmFWCdx5l4Hkl3I1eY=
+github.com/go-kratos/swagger-api v0.1.8 h1:4afwLcDwMut7LyS5b0iarB5p6XTbaJngRvAqDb4Skig=
+github.com/go-kratos/swagger-api v0.1.8/go.mod h1:HMI1NY/OWbjbkZF2z//tEKoL1XpZOzyxOedtBddEyZE=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
 github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
 github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
 github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/form/v4 v4.1.3 h1:SMUgkH+XBQkssHylgYzmy2VV4r37/pBYHgQnyqeBmmM=
+github.com/go-playground/form/v4 v4.1.3/go.mod h1:q1a2BY+AQUUzhl6xA/6hBetay6dEIhMHjgvJiGo6K7U=
 github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
 github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
 github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
@@ -187,18 +218,27 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/glog v0.0.0-20210429001901-424d2337a529 h1:2voWjNECnrZRbfwXxHB1/j8wa6xdKn85B5NzgVL/pTU=
+github.com/golang/glog v0.0.0-20210429001901-424d2337a529/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
 github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
 github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
 github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
 github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
@@ -219,7 +259,9 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -228,8 +270,14 @@ github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -317,6 +365,7 @@ github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKEN
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
 github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
 github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
@@ -341,6 +390,7 @@ github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/
 github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
 github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
@@ -377,6 +427,8 @@ github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042/go.mod h1:TPp
 github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
 github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
+github.com/longXboy/grpc-gateway/v2 v2.0.0-20210707031540-bd2d73d86cee h1:lmk9VXnkwZiLgbQdlM4EfJBZAaTZTfex/hZ9ByQrzqo=
+github.com/longXboy/grpc-gateway/v2 v2.0.0-20210707031540-bd2d73d86cee/go.mod h1:upmbHHZp+gtRNfSk94XgTH+14LqZxzmvgnrp9KEMKRg=
 github.com/lyft/protoc-gen-star v0.5.1/go.mod h1:9toiA3cC7z5uVbODF7kEQ91Xn7XNFkVUl+SrEe+ZORU=
 github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
 github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -516,6 +568,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
 github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4=
 github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ=
+github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc=
 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
@@ -587,7 +641,9 @@ github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPU
 github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
 github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@@ -608,6 +664,8 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
 go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY=
 go.opentelemetry.io/otel v0.16.0/go.mod h1:e4GKElweB8W2gWUqbghw0B8t5MCTccc9212eNHnOHwA=
@@ -674,6 +732,11 @@ golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
 golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -683,6 +746,8 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
 golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
@@ -691,8 +756,10 @@ golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCc
 golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
 golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -711,12 +778,25 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
 golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
@@ -729,13 +809,17 @@ golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qx
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -762,20 +846,33 @@ golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -790,6 +887,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@@ -827,11 +925,34 @@ golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
 golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
@@ -848,11 +969,24 @@ google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E
 google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
 google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
 google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@@ -863,10 +997,31 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
 google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210629200056-84d6f6074151 h1:H/uPzsolsGjhl3CVT6Wb7bK+mf+hmkEvUVu+FBKyNlc=
 google.golang.org/genproto v0.0.0-20210629200056-84d6f6074151/go.mod h1:yiaVoXHpRzHGyxV3o4DktVWY4mSUErTKaeEOq6C3t3U=
+google.golang.org/genproto v0.0.0-20210701191553-46259e63a0a9 h1:HBPuvo39L0DgfVn9eHR3ki/RjZoUFWa+em77e7KFDfs=
+google.golang.org/genproto v0.0.0-20210701191553-46259e63a0a9/go.mod h1:yiaVoXHpRzHGyxV3o4DktVWY4mSUErTKaeEOq6C3t3U=
 google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
@@ -879,7 +1034,11 @@ google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
 google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
 google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
 google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
 google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
 google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
 google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
@@ -896,6 +1055,7 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
 google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
@@ -938,7 +1098,11 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
 honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
 sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
 sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
diff --git a/examples/swagger/helloworld/helloworld.pb.go b/examples/swagger/helloworld/helloworld.pb.go
new file mode 100644
index 00000000..a6f055bf
--- /dev/null
+++ b/examples/swagger/helloworld/helloworld.pb.go
@@ -0,0 +1,251 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.27.1-devel
+// 	protoc        v3.17.2
+// source: helloworld/helloworld.proto
+
+package helloworld
+
+import (
+	reply "github.com/go-kratos/kratos/examples/swagger/reply"
+	_ "github.com/longXboy/grpc-gateway/v2/protoc-gen-openapiv2/options"
+	_ "google.golang.org/genproto/googleapis/api/annotations"
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// The request message containing the user's name.
+type HelloRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *HelloRequest) Reset() {
+	*x = HelloRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_helloworld_helloworld_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *HelloRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*HelloRequest) ProtoMessage() {}
+
+func (x *HelloRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_helloworld_helloworld_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead.
+func (*HelloRequest) Descriptor() ([]byte, []int) {
+	return file_helloworld_helloworld_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *HelloRequest) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+// The response message containing the greetings
+type HelloReply struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Reply *reply.Reply `protobuf:"bytes,1,opt,name=reply,proto3" json:"reply,omitempty"`
+}
+
+func (x *HelloReply) Reset() {
+	*x = HelloReply{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_helloworld_helloworld_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *HelloReply) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*HelloReply) ProtoMessage() {}
+
+func (x *HelloReply) ProtoReflect() protoreflect.Message {
+	mi := &file_helloworld_helloworld_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use HelloReply.ProtoReflect.Descriptor instead.
+func (*HelloReply) Descriptor() ([]byte, []int) {
+	return file_helloworld_helloworld_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *HelloReply) GetReply() *reply.Reply {
+	if x != nil {
+		return x.Reply
+	}
+	return nil
+}
+
+var File_helloworld_helloworld_proto protoreflect.FileDescriptor
+
+var file_helloworld_helloworld_proto_rawDesc = []byte{
+	0x0a, 0x1b, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2f, 0x68, 0x65, 0x6c,
+	0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x68,
+	0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+	0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x11, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x2f, 0x72,
+	0x65, 0x70, 0x6c, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32,
+	0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74,
+	0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x22, 0x0a, 0x0c, 0x48, 0x65,
+	0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
+	0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x30,
+	0x0a, 0x0a, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x22, 0x0a, 0x05,
+	0x72, 0x65, 0x70, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x72, 0x65,
+	0x70, 0x6c, 0x79, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x52, 0x05, 0x72, 0x65, 0x70, 0x6c, 0x79,
+	0x32, 0xa9, 0x01, 0x0a, 0x07, 0x47, 0x72, 0x65, 0x65, 0x74, 0x65, 0x72, 0x12, 0x9d, 0x01, 0x0a,
+	0x08, 0x53, 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x12, 0x18, 0x2e, 0x68, 0x65, 0x6c, 0x6c,
+	0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64,
+	0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x5f, 0x82, 0xd3, 0xe4,
+	0x93, 0x02, 0x14, 0x12, 0x12, 0x2f, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64,
+	0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x92, 0x41, 0x42, 0x22, 0x40, 0x0a, 0x0e, 0x53, 0x61,
+	0x79, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x2e, 0x68, 0x74,
+	0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
+	0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x65, 0x63, 0x6f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2f,
+	0x67, 0x72, 0x70, 0x63, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x42, 0xc9, 0x02, 0x5a,
+	0x4a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b,
+	0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x73, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x2d, 0x61, 0x70,
+	0x69, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
+	0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2f, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64,
+	0x3b, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x92, 0x41, 0xf9, 0x01, 0x12,
+	0xf6, 0x01, 0x0a, 0x13, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x20, 0x65,
+	0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x22, 0x58, 0x0a, 0x14, 0x67, 0x52, 0x50, 0x43, 0x2d,
+	0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x20, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12,
+	0x2e, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
+	0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x65, 0x63, 0x6f, 0x73, 0x79, 0x73, 0x74,
+	0x65, 0x6d, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x1a,
+	0x10, 0x6e, 0x6f, 0x6e, 0x65, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
+	0x6d, 0x2a, 0x5e, 0x0a, 0x14, 0x42, 0x53, 0x44, 0x20, 0x33, 0x2d, 0x43, 0x6c, 0x61, 0x75, 0x73,
+	0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x68, 0x74, 0x74, 0x70, 0x73,
+	0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72,
+	0x70, 0x63, 0x2d, 0x65, 0x63, 0x6f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2f, 0x67, 0x72, 0x70,
+	0x63, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d,
+	0x61, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x2e, 0x74, 0x78,
+	0x74, 0x32, 0x03, 0x31, 0x2e, 0x30, 0x3a, 0x20, 0x0a, 0x15, 0x78, 0x2d, 0x73, 0x6f, 0x6d, 0x65,
+	0x74, 0x68, 0x69, 0x6e, 0x67, 0x2d, 0x73, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x12,
+	0x07, 0x1a, 0x05, 0x79, 0x61, 0x64, 0x64, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_helloworld_helloworld_proto_rawDescOnce sync.Once
+	file_helloworld_helloworld_proto_rawDescData = file_helloworld_helloworld_proto_rawDesc
+)
+
+func file_helloworld_helloworld_proto_rawDescGZIP() []byte {
+	file_helloworld_helloworld_proto_rawDescOnce.Do(func() {
+		file_helloworld_helloworld_proto_rawDescData = protoimpl.X.CompressGZIP(file_helloworld_helloworld_proto_rawDescData)
+	})
+	return file_helloworld_helloworld_proto_rawDescData
+}
+
+var file_helloworld_helloworld_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_helloworld_helloworld_proto_goTypes = []interface{}{
+	(*HelloRequest)(nil), // 0: helloworld.HelloRequest
+	(*HelloReply)(nil),   // 1: helloworld.HelloReply
+	(*reply.Reply)(nil),  // 2: reply.Reply
+}
+var file_helloworld_helloworld_proto_depIdxs = []int32{
+	2, // 0: helloworld.HelloReply.reply:type_name -> reply.Reply
+	0, // 1: helloworld.Greeter.SayHello:input_type -> helloworld.HelloRequest
+	1, // 2: helloworld.Greeter.SayHello:output_type -> helloworld.HelloReply
+	2, // [2:3] is the sub-list for method output_type
+	1, // [1:2] is the sub-list for method input_type
+	1, // [1:1] is the sub-list for extension type_name
+	1, // [1:1] is the sub-list for extension extendee
+	0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_helloworld_helloworld_proto_init() }
+func file_helloworld_helloworld_proto_init() {
+	if File_helloworld_helloworld_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_helloworld_helloworld_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*HelloRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_helloworld_helloworld_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*HelloReply); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_helloworld_helloworld_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_helloworld_helloworld_proto_goTypes,
+		DependencyIndexes: file_helloworld_helloworld_proto_depIdxs,
+		MessageInfos:      file_helloworld_helloworld_proto_msgTypes,
+	}.Build()
+	File_helloworld_helloworld_proto = out.File
+	file_helloworld_helloworld_proto_rawDesc = nil
+	file_helloworld_helloworld_proto_goTypes = nil
+	file_helloworld_helloworld_proto_depIdxs = nil
+}
diff --git a/examples/swagger/helloworld/helloworld.proto b/examples/swagger/helloworld/helloworld.proto
new file mode 100644
index 00000000..77f482ff
--- /dev/null
+++ b/examples/swagger/helloworld/helloworld.proto
@@ -0,0 +1,57 @@
+syntax = "proto3";
+
+package helloworld;
+
+import "google/api/annotations.proto";
+import "reply/reply.proto";
+import "protoc-gen-openapiv2/options/annotations.proto";
+
+option go_package = "github.com/go-kratos/kratos/examples/swagger/helloworld;helloworld";
+
+option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+	info: {
+		title: "Helloworld examples";
+		version: "1.0";
+		contact: {
+			name: "gRPC-Gateway project";
+			url: "https://github.com/grpc-ecosystem/grpc-gateway";
+			email: "none@example.com";
+		};
+		license: {
+			name: "BSD 3-Clause License";
+			url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt";
+		};
+		extensions: {
+			key: "x-something-something";
+			value {
+				string_value: "yadda";
+			}
+		}
+  };
+};
+
+// The greeting service definition.
+service Greeter {
+  // Sends a greeting
+  rpc SayHello (HelloRequest) returns (HelloReply)  {
+        option (google.api.http) = {
+            get: "/helloworld/{name}",
+        };
+        option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
+          external_docs: {
+            url: "https://github.com/grpc-ecosystem/grpc-gateway";
+            description: "SayHello Query";
+          }
+        };
+  }
+}
+
+// The request message containing the user's name.
+message HelloRequest {
+  string name = 1;
+}
+
+// The response message containing the greetings
+message HelloReply {
+  reply.Reply reply = 1;
+}
diff --git a/examples/swagger/helloworld/helloworld_grpc.pb.go b/examples/swagger/helloworld/helloworld_grpc.pb.go
new file mode 100644
index 00000000..4e1c32b3
--- /dev/null
+++ b/examples/swagger/helloworld/helloworld_grpc.pb.go
@@ -0,0 +1,103 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+
+package helloworld
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// GreeterClient is the client API for Greeter service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type GreeterClient interface {
+	// Sends a greeting
+	SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
+}
+
+type greeterClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient {
+	return &greeterClient{cc}
+}
+
+func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {
+	out := new(HelloReply)
+	err := c.cc.Invoke(ctx, "/helloworld.Greeter/SayHello", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// GreeterServer is the server API for Greeter service.
+// All implementations must embed UnimplementedGreeterServer
+// for forward compatibility
+type GreeterServer interface {
+	// Sends a greeting
+	SayHello(context.Context, *HelloRequest) (*HelloReply, error)
+	mustEmbedUnimplementedGreeterServer()
+}
+
+// UnimplementedGreeterServer must be embedded to have forward compatible implementations.
+type UnimplementedGreeterServer struct {
+}
+
+func (UnimplementedGreeterServer) SayHello(context.Context, *HelloRequest) (*HelloReply, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented")
+}
+func (UnimplementedGreeterServer) mustEmbedUnimplementedGreeterServer() {}
+
+// UnsafeGreeterServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to GreeterServer will
+// result in compilation errors.
+type UnsafeGreeterServer interface {
+	mustEmbedUnimplementedGreeterServer()
+}
+
+func RegisterGreeterServer(s grpc.ServiceRegistrar, srv GreeterServer) {
+	s.RegisterService(&Greeter_ServiceDesc, srv)
+}
+
+func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(HelloRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(GreeterServer).SayHello(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/helloworld.Greeter/SayHello",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// Greeter_ServiceDesc is the grpc.ServiceDesc for Greeter service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var Greeter_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "helloworld.Greeter",
+	HandlerType: (*GreeterServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "SayHello",
+			Handler:    _Greeter_SayHello_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "helloworld/helloworld.proto",
+}
diff --git a/examples/swagger/helloworld/helloworld_http.pb.go b/examples/swagger/helloworld/helloworld_http.pb.go
new file mode 100644
index 00000000..d362a4c7
--- /dev/null
+++ b/examples/swagger/helloworld/helloworld_http.pb.go
@@ -0,0 +1,74 @@
+// Code generated by protoc-gen-go-http. DO NOT EDIT.
+// versions:
+// protoc-gen-go-http v2.0.0-rc7
+
+package helloworld
+
+import (
+	context "context"
+	http "github.com/go-kratos/kratos/v2/transport/http"
+	binding "github.com/go-kratos/kratos/v2/transport/http/binding"
+)
+
+// 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 _ = binding.EncodeURL
+
+const _ = http.SupportPackageIsVersion1
+
+type GreeterHTTPServer interface {
+	SayHello(context.Context, *HelloRequest) (*HelloReply, error)
+}
+
+func RegisterGreeterHTTPServer(s *http.Server, srv GreeterHTTPServer) {
+	r := s.Route("/")
+	r.GET("/helloworld/{name}", _Greeter_SayHello0_HTTP_Handler(srv))
+}
+
+func _Greeter_SayHello0_HTTP_Handler(srv GreeterHTTPServer) func(ctx http.Context) error {
+	return func(ctx http.Context) error {
+		var in HelloRequest
+		if err := ctx.BindQuery(&in); err != nil {
+			return err
+		}
+		if err := ctx.BindVars(&in); err != nil {
+			return err
+		}
+		http.SetOperation(ctx, "/helloworld.Greeter/SayHello")
+		h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
+			return srv.SayHello(ctx, req.(*HelloRequest))
+		})
+		out, err := h(ctx, &in)
+		if err != nil {
+			return err
+		}
+		reply := out.(*HelloReply)
+		return ctx.Result(200, reply)
+	}
+}
+
+type GreeterHTTPClient interface {
+	SayHello(ctx context.Context, req *HelloRequest, opts ...http.CallOption) (rsp *HelloReply, err error)
+}
+
+type GreeterHTTPClientImpl struct {
+	cc *http.Client
+}
+
+func NewGreeterHTTPClient(client *http.Client) GreeterHTTPClient {
+	return &GreeterHTTPClientImpl{client}
+}
+
+func (c *GreeterHTTPClientImpl) SayHello(ctx context.Context, in *HelloRequest, opts ...http.CallOption) (*HelloReply, error) {
+	var out HelloReply
+	pattern := "/helloworld/{name}"
+	path := binding.EncodeURL(pattern, in, true)
+	opts = append(opts, http.Operation("/helloworld.Greeter/SayHello"))
+	opts = append(opts, http.PathTemplate(pattern))
+	err := c.cc.Invoke(ctx, "GET", path, nil, &out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return &out, err
+}
diff --git a/examples/swagger/reply/reply.pb.go b/examples/swagger/reply/reply.pb.go
new file mode 100644
index 00000000..8a7bfd06
--- /dev/null
+++ b/examples/swagger/reply/reply.pb.go
@@ -0,0 +1,145 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.8
+// source: reply/reply.proto
+
+package reply
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Reply struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
+}
+
+func (x *Reply) Reset() {
+	*x = Reply{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_reply_reply_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Reply) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Reply) ProtoMessage() {}
+
+func (x *Reply) ProtoReflect() protoreflect.Message {
+	mi := &file_reply_reply_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Reply.ProtoReflect.Descriptor instead.
+func (*Reply) Descriptor() ([]byte, []int) {
+	return file_reply_reply_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Reply) GetValue() string {
+	if x != nil {
+		return x.Value
+	}
+	return ""
+}
+
+var File_reply_reply_proto protoreflect.FileDescriptor
+
+var file_reply_reply_proto_rawDesc = []byte{
+	0x0a, 0x11, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x2f, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x12, 0x05, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x1d, 0x0a, 0x05, 0x52, 0x65,
+	0x70, 0x6c, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74,
+	0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, 0x6f,
+	0x73, 0x2f, 0x73, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x2d, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x78,
+	0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c,
+	0x64, 0x2f, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x3b, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x62, 0x06, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_reply_reply_proto_rawDescOnce sync.Once
+	file_reply_reply_proto_rawDescData = file_reply_reply_proto_rawDesc
+)
+
+func file_reply_reply_proto_rawDescGZIP() []byte {
+	file_reply_reply_proto_rawDescOnce.Do(func() {
+		file_reply_reply_proto_rawDescData = protoimpl.X.CompressGZIP(file_reply_reply_proto_rawDescData)
+	})
+	return file_reply_reply_proto_rawDescData
+}
+
+var file_reply_reply_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_reply_reply_proto_goTypes = []interface{}{
+	(*Reply)(nil), // 0: reply.Reply
+}
+var file_reply_reply_proto_depIdxs = []int32{
+	0, // [0:0] is the sub-list for method output_type
+	0, // [0:0] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_reply_reply_proto_init() }
+func file_reply_reply_proto_init() {
+	if File_reply_reply_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_reply_reply_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Reply); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_reply_reply_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_reply_reply_proto_goTypes,
+		DependencyIndexes: file_reply_reply_proto_depIdxs,
+		MessageInfos:      file_reply_reply_proto_msgTypes,
+	}.Build()
+	File_reply_reply_proto = out.File
+	file_reply_reply_proto_rawDesc = nil
+	file_reply_reply_proto_goTypes = nil
+	file_reply_reply_proto_depIdxs = nil
+}
diff --git a/examples/swagger/reply/reply.proto b/examples/swagger/reply/reply.proto
new file mode 100644
index 00000000..cb51450b
--- /dev/null
+++ b/examples/swagger/reply/reply.proto
@@ -0,0 +1,9 @@
+syntax = "proto3";
+
+package reply;
+
+option go_package = "github.com/go-kratos/kratos/examples/swagger/reply;reply";
+
+message Reply {
+    string value = 1;
+}
\ No newline at end of file
diff --git a/examples/swagger/server/main.go b/examples/swagger/server/main.go
new file mode 100644
index 00000000..9c187b89
--- /dev/null
+++ b/examples/swagger/server/main.go
@@ -0,0 +1,67 @@
+package main
+
+import (
+	"context"
+	"fmt"
+	"os"
+
+	pb "github.com/go-kratos/kratos/examples/swagger/helloworld"
+	reply "github.com/go-kratos/kratos/examples/swagger/reply"
+	"github.com/go-kratos/kratos/v2"
+	"github.com/go-kratos/kratos/v2/errors"
+	"github.com/go-kratos/kratos/v2/log"
+	"github.com/go-kratos/kratos/v2/transport/http"
+	"github.com/go-kratos/swagger-api/openapiv2"
+)
+
+// go build -ldflags "-X main.Version=x.y.z"
+var (
+	// Name is the name of the compiled software.
+	Name = "helloworld"
+	// Version is the version of the compiled software.
+	Version = "v1.0.0"
+)
+
+// server is used to implement helloworld.GreeterServer.
+type server struct {
+	pb.UnimplementedGreeterServer
+}
+
+// SayHello implements helloworld.GreeterServer
+func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
+	if in.Name == "error" {
+		return nil, errors.BadRequest("custom_error", fmt.Sprintf("invalid argument %s", in.Name))
+	}
+	if in.Name == "panic" {
+		panic("grpc panic")
+	}
+
+	return &pb.HelloReply{Reply: &reply.Reply{Value: fmt.Sprintf("Hello %+v", in.Name)}}, nil
+}
+
+func main() {
+	logger := log.NewStdLogger(os.Stdout)
+
+	log := log.NewHelper(logger)
+	s := &server{}
+
+	httpSrv := http.NewServer(http.Address(":8000"))
+	pb.RegisterGreeterHTTPServer(httpSrv, s)
+
+	h := openapiv2.NewHandler()
+	httpSrv.HandlePrefix("/q/", h)
+
+	/*	fs := httpx.FileServer(httpx.Dir("./dist"))
+		httpSrv.HandlePrefix("/swaggerui/", httpx.StripPrefix("/swaggerui/", fs))*/
+
+	app := kratos.New(
+		kratos.Name(Name),
+		kratos.Server(
+			httpSrv,
+		),
+	)
+
+	if err := app.Run(); err != nil {
+		log.Error(err)
+	}
+}
diff --git a/go.mod b/go.mod
index 208a3deb..7716befb 100644
--- a/go.mod
+++ b/go.mod
@@ -5,6 +5,7 @@ go 1.15
 require (
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/fsnotify/fsnotify v1.4.9
+	github.com/go-playground/form/v4 v4.1.3
 	github.com/google/uuid v1.2.0
 	github.com/gorilla/mux v1.8.0
 	github.com/gorilla/schema v1.2.0
diff --git a/go.sum b/go.sum
index d0fc88f5..747dcd1f 100644
--- a/go.sum
+++ b/go.sum
@@ -20,6 +20,11 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
 github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/form v1.10.0 h1:0ybRwhsCPQzo8dC09q8XAVn+peG7Ld927Gbe9twmgv8=
+github.com/go-playground/form v3.1.4+incompatible h1:lvKiHVxE2WvzDIoyMnWcjyiBxKt2+uFJyZcPYWsLnjI=
+github.com/go-playground/form/v4 v4.1.3 h1:SMUgkH+XBQkssHylgYzmy2VV4r37/pBYHgQnyqeBmmM=
+github.com/go-playground/form/v4 v4.1.3/go.mod h1:q1a2BY+AQUUzhl6xA/6hBetay6dEIhMHjgvJiGo6K7U=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
diff --git a/third_party/protoc-gen-openapiv2/options/annotations.proto b/third_party/protoc-gen-openapiv2/options/annotations.proto
new file mode 100644
index 00000000..0ece3169
--- /dev/null
+++ b/third_party/protoc-gen-openapiv2/options/annotations.proto
@@ -0,0 +1,44 @@
+syntax = "proto3";
+
+package grpc.gateway.protoc_gen_openapiv2.options;
+
+option go_package = "github.com/longXboy/grpc-gateway/v2/protoc-gen-openapiv2/options";
+
+import "google/protobuf/descriptor.proto";
+import "protoc-gen-openapiv2/options/openapiv2.proto";
+
+extend google.protobuf.FileOptions {
+  // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+  //
+  // All IDs are the same, as assigned. It is okay that they are the same, as they extend
+  // different descriptor messages.
+  Swagger openapiv2_swagger = 1042;
+}
+extend google.protobuf.MethodOptions {
+  // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+  //
+  // All IDs are the same, as assigned. It is okay that they are the same, as they extend
+  // different descriptor messages.
+  Operation openapiv2_operation = 1042;
+}
+extend google.protobuf.MessageOptions {
+  // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+  //
+  // All IDs are the same, as assigned. It is okay that they are the same, as they extend
+  // different descriptor messages.
+  Schema openapiv2_schema = 1042;
+}
+extend google.protobuf.ServiceOptions {
+  // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+  //
+  // All IDs are the same, as assigned. It is okay that they are the same, as they extend
+  // different descriptor messages.
+  Tag openapiv2_tag = 1042;
+}
+extend google.protobuf.FieldOptions {
+  // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project.
+  //
+  // All IDs are the same, as assigned. It is okay that they are the same, as they extend
+  // different descriptor messages.
+  JSONSchema openapiv2_field = 1042;
+}
diff --git a/third_party/protoc-gen-openapiv2/options/openapiv2.proto b/third_party/protoc-gen-openapiv2/options/openapiv2.proto
new file mode 100644
index 00000000..17fba868
--- /dev/null
+++ b/third_party/protoc-gen-openapiv2/options/openapiv2.proto
@@ -0,0 +1,645 @@
+syntax = "proto3";
+
+package grpc.gateway.protoc_gen_openapiv2.options;
+
+option go_package = "github.com/longXboy/grpc-gateway/v2/protoc-gen-openapiv2/options";
+
+import "google/protobuf/struct.proto";
+
+// Scheme describes the schemes supported by the OpenAPI Swagger
+// and Operation objects.
+enum Scheme {
+  UNKNOWN = 0;
+  HTTP = 1;
+  HTTPS = 2;
+  WS = 3;
+  WSS = 4;
+}
+
+// `Swagger` is a representation of OpenAPI v2 specification's Swagger object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#swaggerObject
+//
+// Example:
+//
+//  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//    info: {
+//      title: "Echo API";
+//      version: "1.0";
+//      description: ";
+//      contact: {
+//        name: "gRPC-Gateway project";
+//        url: "https://github.com/grpc-ecosystem/grpc-gateway";
+//        email: "none@example.com";
+//      };
+//      license: {
+//        name: "BSD 3-Clause License";
+//        url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt";
+//      };
+//    };
+//    schemes: HTTPS;
+//    consumes: "application/json";
+//    produces: "application/json";
+//  };
+//
+message Swagger {
+  // Specifies the OpenAPI Specification version being used. It can be
+  // used by the OpenAPI UI and other clients to interpret the API listing. The 
+  // value MUST be "2.0".
+  string swagger = 1;
+  // Provides metadata about the API. The metadata can be used by the 
+  // clients if needed.
+  Info info = 2;
+  // The host (name or ip) serving the API. This MUST be the host only and does 
+  // not include the scheme nor sub-paths. It MAY include a port. If the host is
+  // not included, the host serving the documentation is to be used (including
+  // the port). The host does not support path templating.
+  string host = 3;
+  // The base path on which the API is served, which is relative to the host. If
+  // it is not included, the API is served directly under the host. The value 
+  // MUST start with a leading slash (/). The basePath does not support path
+  // templating.
+  // Note that using `base_path` does not change the endpoint paths that are 
+  // generated in the resulting OpenAPI file. If you wish to use `base_path`
+  // with relatively generated OpenAPI paths, the `base_path` prefix must be 
+  // manually removed from your `google.api.http` paths and your code changed to 
+  // serve the API from the `base_path`.
+  string base_path = 4;
+  // The transfer protocol of the API. Values MUST be from the list: "http",
+  // "https", "ws", "wss". If the schemes is not included, the default scheme to
+  // be used is the one used to access the OpenAPI definition itself.
+  repeated Scheme schemes = 5;
+  // A list of MIME types the APIs can consume. This is global to all APIs but 
+  // can be overridden on specific API calls. Value MUST be as described under
+  // Mime Types.
+  repeated string consumes = 6;
+  // A list of MIME types the APIs can produce. This is global to all APIs but
+  // can be overridden on specific API calls. Value MUST be as described under
+  // Mime Types.
+  repeated string produces = 7;
+  // field 8 is reserved for 'paths'.
+  reserved 8;
+  // field 9 is reserved for 'definitions', which at this time are already
+  // exposed as and customizable as proto messages.
+  reserved 9;
+  // An object to hold responses that can be used across operations. This
+  // property does not define global responses for all operations.
+  map<string, Response> responses = 10;
+  // Security scheme definitions that can be used across the specification.
+  SecurityDefinitions security_definitions = 11;
+  // A declaration of which security schemes are applied for the API as a whole.
+  // The list of values describes alternative security schemes that can be used 
+  // (that is, there is a logical OR between the security requirements). 
+  // Individual operations can override this definition.
+  repeated SecurityRequirement security = 12;
+  // field 13 is reserved for 'tags', which are supposed to be exposed as and
+  // customizable as proto services. TODO(ivucica): add processing of proto
+  // service objects into OpenAPI v2 Tag objects.
+  reserved 13;
+  // Additional external documentation.
+  ExternalDocumentation external_docs = 14;
+  map<string, google.protobuf.Value> extensions = 15;
+}
+
+// `Operation` is a representation of OpenAPI v2 specification's Operation object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#operationObject
+//
+// Example:
+//
+//  service EchoService {
+//    rpc Echo(SimpleMessage) returns (SimpleMessage) {
+//      option (google.api.http) = {
+//        get: "/v1/example/echo/{id}"
+//      };
+//
+//      option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
+//        summary: "Get a message.";
+//        operation_id: "getMessage";
+//        tags: "echo";
+//        responses: {
+//          key: "200"
+//            value: {
+//            description: "OK";
+//          }
+//        }
+//      };
+//    }
+//  }
+message Operation {
+  // A list of tags for API documentation control. Tags can be used for logical
+  // grouping of operations by resources or any other qualifier.
+  repeated string tags = 1;
+  // A short summary of what the operation does. For maximum readability in the
+  // swagger-ui, this field SHOULD be less than 120 characters.
+  string summary = 2;
+  // A verbose explanation of the operation behavior. GFM syntax can be used for
+  // rich text representation.
+  string description = 3;
+  // Additional external documentation for this operation.
+  ExternalDocumentation external_docs = 4;
+  // Unique string used to identify the operation. The id MUST be unique among
+  // all operations described in the API. Tools and libraries MAY use the
+  // operationId to uniquely identify an operation, therefore, it is recommended
+  // to follow common programming naming conventions.
+  string operation_id = 5;
+  // A list of MIME types the operation can consume. This overrides the consumes
+  // definition at the OpenAPI Object. An empty value MAY be used to clear the
+  // global definition. Value MUST be as described under Mime Types.
+  repeated string consumes = 6;
+  // A list of MIME types the operation can produce. This overrides the produces
+  // definition at the OpenAPI Object. An empty value MAY be used to clear the
+  // global definition. Value MUST be as described under Mime Types.
+  repeated string produces = 7;
+  // field 8 is reserved for 'parameters'.
+  reserved 8;
+  // The list of possible responses as they are returned from executing this
+  // operation.
+  map<string, Response> responses = 9;
+  // The transfer protocol for the operation. Values MUST be from the list:
+  // "http", "https", "ws", "wss". The value overrides the OpenAPI Object
+  // schemes definition.
+  repeated Scheme schemes = 10;
+  // Declares this operation to be deprecated. Usage of the declared operation
+  // should be refrained. Default value is false.
+  bool deprecated = 11;
+  // A declaration of which security schemes are applied for this operation. The
+  // list of values describes alternative security schemes that can be used
+  // (that is, there is a logical OR between the security requirements). This
+  // definition overrides any declared top-level security. To remove a top-level
+  // security declaration, an empty array can be used.
+  repeated SecurityRequirement security = 12;
+  map<string, google.protobuf.Value> extensions = 13;
+}
+
+// `Header` is a representation of OpenAPI v2 specification's Header object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#headerObject
+//
+message Header {
+  // `Description` is a short description of the header.
+  string description = 1;
+  // The type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported.
+  string type = 2;
+  // `Format` The extending format for the previously mentioned type.
+  string format = 3;
+  // field 4 is reserved for 'items', but in OpenAPI-specific way.
+  reserved 4;
+  // field 5 is reserved `Collection Format` Determines the format of the array if type array is used.
+  reserved 5;
+  // `Default` Declares the value of the header that the server will use if none is provided.
+  // See: https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2.
+  // Unlike JSON Schema this value MUST conform to the defined type for the header.
+  string default = 6;
+  // field 7 is reserved for 'maximum'.
+  reserved 7;
+  // field 8 is reserved for 'exclusiveMaximum'.
+  reserved 8;
+  // field 9 is reserved for 'minimum'.
+  reserved 9;
+  // field 10 is reserved for 'exclusiveMinimum'.
+  reserved 10;
+  // field 11 is reserved for 'maxLength'.
+  reserved 11;
+  // field 12 is reserved for 'minLength'.
+  reserved 12;
+  // 'Pattern' See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3.
+  string pattern = 13;
+  // field 14 is reserved for 'maxItems'.
+  reserved 14;
+  // field 15 is reserved for 'minItems'.
+  reserved 15;
+  // field 16 is reserved for 'uniqueItems'.
+  reserved 16;
+  // field 17 is reserved for 'enum'.
+  reserved 17;
+  // field 18 is reserved for 'multipleOf'.
+  reserved 18;
+}
+
+// `Response` is a representation of OpenAPI v2 specification's Response object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responseObject
+//
+message Response {
+  // `Description` is a short description of the response.
+  // GFM syntax can be used for rich text representation.
+  string description = 1;
+  // `Schema` optionally defines the structure of the response.
+  // If `Schema` is not provided, it means there is no content to the response.
+  Schema schema = 2;
+  // `Headers` A list of headers that are sent with the response.
+  // `Header` name is expected to be a string in the canonical format of the MIME header key
+  // See: https://golang.org/pkg/net/textproto/#CanonicalMIMEHeaderKey
+  map<string, Header> headers = 3;
+  // `Examples` gives per-mimetype response examples.
+  // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object
+  map<string, string> examples = 4;
+  map<string, google.protobuf.Value> extensions = 5;
+}
+
+// `Info` is a representation of OpenAPI v2 specification's Info object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#infoObject
+//
+// Example:
+//
+//  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//    info: {
+//      title: "Echo API";
+//      version: "1.0";
+//      description: ";
+//      contact: {
+//        name: "gRPC-Gateway project";
+//        url: "https://github.com/grpc-ecosystem/grpc-gateway";
+//        email: "none@example.com";
+//      };
+//      license: {
+//        name: "BSD 3-Clause License";
+//        url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt";
+//      };
+//    };
+//    ...
+//  };
+//
+message Info {
+  // The title of the application.
+  string title = 1;
+  // A short description of the application. GFM syntax can be used for rich
+  // text representation.
+  string description = 2;
+  // The Terms of Service for the API.
+  string terms_of_service = 3;
+  // The contact information for the exposed API.
+  Contact contact = 4;
+  // The license information for the exposed API.
+  License license = 5;
+  // Provides the version of the application API (not to be confused
+  // with the specification version).
+  string version = 6;
+  map<string, google.protobuf.Value> extensions = 7;
+}
+
+// `Contact` is a representation of OpenAPI v2 specification's Contact object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#contactObject
+//
+// Example:
+//
+//  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//    info: {
+//      ...
+//      contact: {
+//        name: "gRPC-Gateway project";
+//        url: "https://github.com/grpc-ecosystem/grpc-gateway";
+//        email: "none@example.com";
+//      };
+//      ...
+//    };
+//    ...
+//  };
+//
+message Contact {
+  // The identifying name of the contact person/organization.
+  string name = 1;
+  // The URL pointing to the contact information. MUST be in the format of a
+  // URL.
+  string url = 2;
+  // The email address of the contact person/organization. MUST be in the format
+  // of an email address.
+  string email = 3;
+}
+
+// `License` is a representation of OpenAPI v2 specification's License object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#licenseObject
+//
+// Example:
+//
+//  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//    info: {
+//      ...
+//      license: {
+//        name: "BSD 3-Clause License";
+//        url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt";
+//      };
+//      ...
+//    };
+//    ...
+//  };
+//
+message License {
+  // The license name used for the API.
+  string name = 1;
+  // A URL to the license used for the API. MUST be in the format of a URL.
+  string url = 2;
+}
+
+// `ExternalDocumentation` is a representation of OpenAPI v2 specification's
+// ExternalDocumentation object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#externalDocumentationObject
+//
+// Example:
+//
+//  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
+//    ...
+//    external_docs: {
+//      description: "More about gRPC-Gateway";
+//      url: "https://github.com/grpc-ecosystem/grpc-gateway";
+//    }
+//    ...
+//  };
+//
+message ExternalDocumentation {
+  // A short description of the target documentation. GFM syntax can be used for
+  // rich text representation.
+  string description = 1;
+  // The URL for the target documentation. Value MUST be in the format
+  // of a URL.
+  string url = 2;
+}
+
+// `Schema` is a representation of OpenAPI v2 specification's Schema object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+//
+message Schema {
+  JSONSchema json_schema = 1;
+  // Adds support for polymorphism. The discriminator is the schema property
+  // name that is used to differentiate between other schema that inherit this
+  // schema. The property name used MUST be defined at this schema and it MUST
+  // be in the required property list. When used, the value MUST be the name of
+  // this schema or any schema that inherits it.
+  string discriminator = 2;
+  // Relevant only for Schema "properties" definitions. Declares the property as
+  // "read only". This means that it MAY be sent as part of a response but MUST
+  // NOT be sent as part of the request. Properties marked as readOnly being
+  // true SHOULD NOT be in the required list of the defined schema. Default
+  // value is false.
+  bool read_only = 3;
+  // field 4 is reserved for 'xml'.
+  reserved 4;
+  // Additional external documentation for this schema.
+  ExternalDocumentation external_docs = 5;
+  // A free-form property to include an example of an instance for this schema in JSON.
+  // This is copied verbatim to the output.
+  string example = 6;
+}
+
+// `JSONSchema` represents properties from JSON Schema taken, and as used, in
+// the OpenAPI v2 spec.
+//
+// This includes changes made by OpenAPI v2.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+//
+// See also: https://cswr.github.io/JsonSchema/spec/basic_types/,
+// https://github.com/json-schema-org/json-schema-spec/blob/master/schema.json
+//
+// Example:
+//
+//  message SimpleMessage {
+//    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
+//      json_schema: {
+//        title: "SimpleMessage"
+//        description: "A simple message."
+//        required: ["id"]
+//      }
+//    };
+//
+//    // Id represents the message identifier.
+//    string id = 1; [
+//        (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
+//          {description: "The unique identifier of the simple message."
+//        }];
+//  }
+//
+message JSONSchema {
+  // field 1 is reserved for '$id', omitted from OpenAPI v2.
+  reserved 1;
+  // field 2 is reserved for '$schema', omitted from OpenAPI v2.
+  reserved 2;
+  // Ref is used to define an external reference to include in the message.
+  // This could be a fully qualified proto message reference, and that type must
+  // be imported into the protofile. If no message is identified, the Ref will
+  // be used verbatim in the output.
+  // For example:
+  //  `ref: ".google.protobuf.Timestamp"`.
+  string ref = 3;
+  // field 4 is reserved for '$comment', omitted from OpenAPI v2.
+  reserved 4;
+  // The title of the schema.
+  string title = 5;
+  // A short description of the schema.
+  string description = 6;
+  string default = 7;
+  bool read_only = 8;
+  // A free-form property to include a JSON example of this field. This is copied
+  // verbatim to the output swagger.json. Quotes must be escaped.
+  // This property is the same for 2.0 and 3.0.0 https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/3.0.0.md#schemaObject  https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject
+  string example = 9;
+  double multiple_of = 10;
+  // Maximum represents an inclusive upper limit for a numeric instance. The 
+  // value of MUST be a number, 
+  double maximum = 11;
+  bool exclusive_maximum = 12;
+  // minimum represents an inclusive lower limit for a numeric instance. The 
+  // value of MUST be a number, 
+  double minimum = 13;
+  bool exclusive_minimum = 14;
+  uint64 max_length = 15;
+  uint64 min_length = 16;
+  string pattern = 17;
+  // field 18 is reserved for 'additionalItems', omitted from OpenAPI v2.
+  reserved 18;
+  // field 19 is reserved for 'items', but in OpenAPI-specific way.
+  // TODO(ivucica): add 'items'?
+  reserved 19;
+  uint64 max_items = 20;
+  uint64 min_items = 21;
+  bool unique_items = 22;
+  // field 23 is reserved for 'contains', omitted from OpenAPI v2.
+  reserved 23;
+  uint64 max_properties = 24;
+  uint64 min_properties = 25;
+  repeated string required = 26;
+  // field 27 is reserved for 'additionalProperties', but in OpenAPI-specific
+  // way. TODO(ivucica): add 'additionalProperties'?
+  reserved 27;
+  // field 28 is reserved for 'definitions', omitted from OpenAPI v2.
+  reserved 28;
+  // field 29 is reserved for 'properties', but in OpenAPI-specific way.
+  // TODO(ivucica): add 'additionalProperties'?
+  reserved 29;
+  // following fields are reserved, as the properties have been omitted from
+  // OpenAPI v2:
+  // patternProperties, dependencies, propertyNames, const
+  reserved 30 to 33;
+  // Items in 'array' must be unique.
+  repeated string array = 34;
+
+  enum JSONSchemaSimpleTypes {
+    UNKNOWN = 0;
+    ARRAY = 1;
+    BOOLEAN = 2;
+    INTEGER = 3;
+    NULL = 4;
+    NUMBER = 5;
+    OBJECT = 6;
+    STRING = 7;
+  }
+
+  repeated JSONSchemaSimpleTypes type = 35;
+  // `Format`
+  string format = 36;
+  // following fields are reserved, as the properties have been omitted from 
+  // OpenAPI v2: contentMediaType, contentEncoding, if, then, else
+  reserved 37 to 41;
+  // field 42 is reserved for 'allOf', but in OpenAPI-specific way.
+  // TODO(ivucica): add 'allOf'?
+  reserved 42;
+  // following fields are reserved, as the properties have been omitted from
+  // OpenAPI v2:
+  // anyOf, oneOf, not
+  reserved 43 to 45;
+  // Items in `enum` must be unique https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1
+  repeated string enum = 46;
+}
+
+// `Tag` is a representation of OpenAPI v2 specification's Tag object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#tagObject
+//
+message Tag {
+  // field 1 is reserved for 'name'. In our generator, this is (to be) extracted
+  // from the name of proto service, and thus not exposed to the user, as
+  // changing tag object's name would break the link to the references to the
+  // tag in individual operation specifications.
+  //
+  // TODO(ivucica): Add 'name' property. Use it to allow override of the name of
+  // global Tag object, then use that name to reference the tag throughout the
+  // OpenAPI file.
+  reserved 1;
+  // A short description for the tag. GFM syntax can be used for rich text 
+  // representation.
+  string description = 2;
+  // Additional external documentation for this tag.
+  ExternalDocumentation external_docs = 3;
+}
+
+// `SecurityDefinitions` is a representation of OpenAPI v2 specification's
+// Security Definitions object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityDefinitionsObject
+//
+// A declaration of the security schemes available to be used in the
+// specification. This does not enforce the security schemes on the operations
+// and only serves to provide the relevant details for each scheme.
+message SecurityDefinitions {
+  // A single security scheme definition, mapping a "name" to the scheme it
+  // defines.
+  map<string, SecurityScheme> security = 1;
+}
+
+// `SecurityScheme` is a representation of OpenAPI v2 specification's
+// Security Scheme object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securitySchemeObject
+//
+// Allows the definition of a security scheme that can be used by the
+// operations. Supported schemes are basic authentication, an API key (either as
+// a header or as a query parameter) and OAuth2's common flows (implicit,
+// password, application and access code).
+message SecurityScheme {
+  // The type of the security scheme. Valid values are "basic",
+  // "apiKey" or "oauth2".
+  enum Type {
+    TYPE_INVALID = 0;
+    TYPE_BASIC = 1;
+    TYPE_API_KEY = 2;
+    TYPE_OAUTH2 = 3;
+  }
+
+  // The location of the API key. Valid values are "query" or "header".
+  enum In {
+    IN_INVALID = 0;
+    IN_QUERY = 1;
+    IN_HEADER = 2;
+  }
+
+  // The flow used by the OAuth2 security scheme. Valid values are
+  // "implicit", "password", "application" or "accessCode".
+  enum Flow {
+    FLOW_INVALID = 0;
+    FLOW_IMPLICIT = 1;
+    FLOW_PASSWORD = 2;
+    FLOW_APPLICATION = 3;
+    FLOW_ACCESS_CODE = 4;
+  }
+
+  // The type of the security scheme. Valid values are "basic",
+  // "apiKey" or "oauth2".
+  Type type = 1;
+  // A short description for security scheme.
+  string description = 2;
+  // The name of the header or query parameter to be used.
+  // Valid for apiKey.
+  string name = 3;
+  // The location of the API key. Valid values are "query" or
+  // "header".
+  // Valid for apiKey.
+  In in = 4;
+  // The flow used by the OAuth2 security scheme. Valid values are
+  // "implicit", "password", "application" or "accessCode".
+  // Valid for oauth2.
+  Flow flow = 5;
+  // The authorization URL to be used for this flow. This SHOULD be in
+  // the form of a URL.
+  // Valid for oauth2/implicit and oauth2/accessCode.
+  string authorization_url = 6;
+  // The token URL to be used for this flow. This SHOULD be in the
+  // form of a URL.
+  // Valid for oauth2/password, oauth2/application and oauth2/accessCode.
+  string token_url = 7;
+  // The available scopes for the OAuth2 security scheme.
+  // Valid for oauth2.
+  Scopes scopes = 8;
+  map<string, google.protobuf.Value> extensions = 9;
+}
+
+// `SecurityRequirement` is a representation of OpenAPI v2 specification's
+// Security Requirement object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityRequirementObject
+//
+// Lists the required security schemes to execute this operation. The object can
+// have multiple security schemes declared in it which are all required (that
+// is, there is a logical AND between the schemes).
+//
+// The name used for each property MUST correspond to a security scheme
+// declared in the Security Definitions.
+message SecurityRequirement {
+  // If the security scheme is of type "oauth2", then the value is a list of
+  // scope names required for the execution. For other security scheme types,
+  // the array MUST be empty.
+  message SecurityRequirementValue {
+    repeated string scope = 1;
+  }
+  // Each name must correspond to a security scheme which is declared in
+  // the Security Definitions. If the security scheme is of type "oauth2",
+  // then the value is a list of scope names required for the execution.
+  // For other security scheme types, the array MUST be empty.
+  map<string, SecurityRequirementValue> security_requirement = 1;
+}
+
+// `Scopes` is a representation of OpenAPI v2 specification's Scopes object.
+//
+// See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#scopesObject
+//
+// Lists the available scopes for an OAuth2 security scheme.
+message Scopes {
+  // Maps between a name of a scope to a short description of it (as the value
+  // of the property).
+  map<string, string> scope = 1;
+}
\ No newline at end of file
diff --git a/transport/http/binding/bind.go b/transport/http/binding/bind.go
index d45a9581..3155d61e 100644
--- a/transport/http/binding/bind.go
+++ b/transport/http/binding/bind.go
@@ -4,15 +4,13 @@ import (
 	"net/http"
 	"net/url"
 
-	"google.golang.org/protobuf/proto"
+	"github.com/go-kratos/kratos/v2/encoding"
+	"github.com/go-kratos/kratos/v2/encoding/form"
 )
 
 // 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)
+	return encoding.GetCodec(form.Name).Unmarshal([]byte(vars.Encode()), target)
 }
 
 // BindForm bind form parameters to target.
@@ -20,8 +18,5 @@ func BindForm(req *http.Request, target interface{}) error {
 	if err := req.ParseForm(); err != nil {
 		return err
 	}
-	if msg, ok := target.(proto.Message); ok {
-		return mapProto(msg, req.Form)
-	}
-	return mapForm(target, req.Form)
+	return encoding.GetCodec(form.Name).Unmarshal([]byte(req.Form.Encode()), target)
 }
diff --git a/transport/http/binding/encode.go b/transport/http/binding/encode.go
index a4b976e8..f7a1564e 100644
--- a/transport/http/binding/encode.go
+++ b/transport/http/binding/encode.go
@@ -3,16 +3,17 @@ package binding
 import (
 	"encoding/base64"
 	"fmt"
-	"net/url"
 	"reflect"
 	"regexp"
 	"strconv"
 	"strings"
 	"time"
 
+	"github.com/go-kratos/kratos/v2/encoding/form"
+
 	"google.golang.org/genproto/protobuf/field_mask"
 	"google.golang.org/protobuf/proto"
-	"google.golang.org/protobuf/reflect/protoreflect"
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	"google.golang.org/protobuf/types/known/durationpb"
 	"google.golang.org/protobuf/types/known/timestamppb"
 	"google.golang.org/protobuf/types/known/wrapperspb"
@@ -41,7 +42,7 @@ func EncodeURL(pathTemplate string, msg proto.Message, needQuery bool) string {
 		return in
 	})
 	if needQuery {
-		u, err := EncodeQuery(msg)
+		u, err := form.EncodeMap(msg)
 		if err == nil && len(u) > 0 {
 			for key := range pathParams {
 				delete(u, key)
@@ -55,25 +56,12 @@ func EncodeURL(pathTemplate string, msg proto.Message, needQuery bool) string {
 	return path
 }
 
-// EncodeQuery encode proto message to url query.
-func EncodeQuery(msg proto.Message) (url.Values, error) {
-	if msg == nil || (reflect.ValueOf(msg).Kind() == reflect.Ptr && reflect.ValueOf(msg).IsNil()) {
-		return url.Values{}, nil
-	}
-	u := make(url.Values)
-	err := encodeByField(u, "", msg.ProtoReflect())
-	if err != nil {
-		return nil, err
-	}
-	return u, nil
-}
-
 func getValueByField(v protoreflect.Message, fieldPath []string) (string, error) {
 	var fd protoreflect.FieldDescriptor
 	for i, fieldName := range fieldPath {
 		fields := v.Descriptor().Fields()
-		if fd = fields.ByName(protoreflect.Name(fieldName)); fd == nil {
-			fd = fields.ByJSONName(fieldName)
+		if fd = fields.ByJSONName(fieldName); fd == nil {
+			fd = fields.ByName(protoreflect.Name(fieldName))
 			if fd == nil {
 				return "", fmt.Errorf("field path not found: %q", fieldName)
 			}
@@ -89,105 +77,6 @@ func getValueByField(v protoreflect.Message, fieldPath []string) (string, error)
 	return encodeField(fd, v.Get(fd))
 }
 
-func encodeByField(u url.Values, path string, v protoreflect.Message) error {
-	for i := 0; i < v.Descriptor().Fields().Len(); i++ {
-		fd := v.Descriptor().Fields().Get(i)
-		var key string
-		var newPath string
-		if fd.HasJSONName() {
-			key = fd.JSONName()
-		} else {
-			key = fd.TextName()
-		}
-		if path == "" {
-			newPath = key
-		} else {
-			newPath = path + "." + key
-		}
-
-		if of := fd.ContainingOneof(); of != nil {
-			if f := v.WhichOneof(of); f != nil {
-				if f != fd {
-					continue
-				}
-			}
-			continue
-		}
-		switch {
-		case fd.IsList():
-			if v.Get(fd).List().Len() > 0 {
-				list, err := encodeRepeatedField(fd, v.Get(fd).List())
-				if err != nil {
-					return err
-				}
-				u[newPath] = list
-			}
-		case fd.IsMap():
-			if v.Get(fd).Map().Len() > 0 {
-				m, err := encodeMapField(fd, v.Get(fd).Map())
-				if err != nil {
-					return err
-				}
-				for k, value := range m {
-					u[fmt.Sprintf("%s[%s]", newPath, k)] = []string{value}
-				}
-			}
-		case (fd.Kind() == protoreflect.MessageKind) || (fd.Kind() == protoreflect.GroupKind):
-			value, err := encodeMessage(fd.Message(), v.Get(fd))
-			if err == nil {
-				u[newPath] = []string{value}
-				continue
-			}
-			err = encodeByField(u, newPath, v.Get(fd).Message())
-			if err != nil {
-				return err
-			}
-		default:
-			value, err := encodeField(fd, v.Get(fd))
-			if err != nil {
-				return err
-			}
-			u[newPath] = []string{value}
-		}
-	}
-	return nil
-}
-
-func encodeMessageField(fieldDescriptor protoreflect.FieldDescriptor, msgValue protoreflect.Message) (string, error) {
-	return encodeField(fieldDescriptor, msgValue.Get(fieldDescriptor))
-}
-
-func encodeRepeatedField(fieldDescriptor protoreflect.FieldDescriptor, list protoreflect.List) ([]string, error) {
-	var values []string
-	for i := 0; i < list.Len(); i++ {
-		value, err := encodeField(fieldDescriptor, list.Get(i))
-		if err != nil {
-			return nil, err
-		}
-		values = append(values, value)
-	}
-
-	return values, nil
-}
-
-func encodeMapField(fieldDescriptor protoreflect.FieldDescriptor, mp protoreflect.Map) (map[string]string, error) {
-	m := make(map[string]string)
-	mp.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
-		key, err := encodeField(fieldDescriptor.MapValue(), k.Value())
-		if err != nil {
-			return false
-		}
-		value, err := encodeField(fieldDescriptor.MapValue(), v)
-		if err != nil {
-			return false
-		}
-		m[key] = value
-		return true
-	})
-
-	return m, nil
-}
-
 func encodeField(fieldDescriptor protoreflect.FieldDescriptor, value protoreflect.Value) (string, error) {
 	switch fieldDescriptor.Kind() {
 	case protoreflect.BoolKind:
diff --git a/transport/http/binding/form.go b/transport/http/binding/form.go
deleted file mode 100644
index 5c83bc12..00000000
--- a/transport/http/binding/form.go
+++ /dev/null
@@ -1,385 +0,0 @@
-package binding
-
-// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
-// Use of this source code is governed by a MIT style
-// license that can be found in the LICENSE file.
-
-import (
-	"encoding/json"
-	"errors"
-	"fmt"
-	"reflect"
-	"strconv"
-	"strings"
-	"time"
-)
-
-var (
-	errUnknownType = errors.New("unknown type")
-	emptyField     = reflect.StructField{}
-)
-
-func mapForm(ptr interface{}, form map[string][]string) error {
-	return mapFormByTag(ptr, form, "json")
-}
-
-func mapFormByTag(ptr interface{}, form map[string][]string, tag string) error {
-	ptrVal := reflect.ValueOf(ptr)
-	var pointed interface{}
-	if ptrVal.Kind() == reflect.Ptr {
-		ptrVal = ptrVal.Elem()
-		pointed = ptrVal.Interface()
-	}
-	if ptrVal.Kind() == reflect.Map &&
-		ptrVal.Type().Key().Kind() == reflect.String {
-		if pointed != nil {
-			ptr = pointed
-		}
-		return setFormMap(ptr, form)
-	}
-	return mappingByPtr(ptr, formSource(form), tag)
-}
-
-// setter tries to set value on a walking by fields of a struct
-type setter interface {
-	TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSetted bool, err error)
-}
-
-type formSource map[string][]string
-
-var _ setter = formSource(nil)
-
-// TrySet tries to set a value by request's form source (like map[string][]string)
-func (form formSource) TrySet(value reflect.Value, field reflect.StructField, tagValue string, opt setOptions) (isSetted bool, err error) {
-	return setByForm(value, field, form, tagValue, opt)
-}
-
-func mappingByPtr(ptr interface{}, setter setter, tag string) error {
-	_, err := mapping(reflect.ValueOf(ptr), emptyField, setter, tag)
-	return err
-}
-
-func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
-	if field.Tag.Get(tag) == "-" { // just ignoring this field
-		return false, nil
-	}
-
-	var vKind = value.Kind()
-
-	if vKind == reflect.Ptr {
-		var isNew bool
-		vPtr := value
-		if value.IsNil() {
-			isNew = true
-			vPtr = reflect.New(value.Type().Elem())
-		}
-		isSetted, err := mapping(vPtr.Elem(), field, setter, tag)
-		if err != nil {
-			return false, err
-		}
-		if isNew && isSetted {
-			value.Set(vPtr)
-		}
-		return isSetted, nil
-	}
-
-	if vKind != reflect.Struct || !field.Anonymous {
-		ok, err := tryToSetValue(value, field, setter, tag)
-		if err != nil {
-			return false, err
-		}
-		if ok {
-			return true, nil
-		}
-	}
-
-	if vKind == reflect.Struct {
-		tValue := value.Type()
-
-		var isSetted bool
-		for i := 0; i < value.NumField(); i++ {
-			sf := tValue.Field(i)
-			if sf.PkgPath != "" && !sf.Anonymous { // unexported
-				continue
-			}
-			ok, err := mapping(value.Field(i), tValue.Field(i), setter, tag)
-			if err != nil {
-				return false, err
-			}
-			isSetted = isSetted || ok
-		}
-		return isSetted, nil
-	}
-	return false, nil
-}
-
-type setOptions struct {
-	isDefaultExists bool
-	defaultValue    string
-}
-
-func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
-	var tagValue string
-	var setOpt setOptions
-
-	tagValue = field.Tag.Get(tag)
-	tagValue, opts := head(tagValue, ",")
-
-	if tagValue == "" { // default value is FieldName
-		tagValue = field.Name
-	}
-	if tagValue == "" { // when field is "emptyField" variable
-		return false, nil
-	}
-
-	var opt string
-	for len(opts) > 0 {
-		opt, opts = head(opts, ",")
-
-		if k, v := head(opt, "="); k == "default" {
-			setOpt.isDefaultExists = true
-			setOpt.defaultValue = v
-		}
-	}
-
-	return setter.TrySet(value, field, tagValue, setOpt)
-}
-
-func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, tagValue string, opt setOptions) (isSetted bool, err error) {
-	vs, ok := form[tagValue]
-	if !ok && !opt.isDefaultExists {
-		return false, nil
-	}
-
-	switch value.Kind() {
-	case reflect.Slice:
-		if !ok {
-			vs = []string{opt.defaultValue}
-		}
-		return true, setSlice(vs, value, field)
-	case reflect.Array:
-		if !ok {
-			vs = []string{opt.defaultValue}
-		}
-		if len(vs) != value.Len() {
-			return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String())
-		}
-		return true, setArray(vs, value, field)
-	default:
-		var val string
-		if !ok {
-			val = opt.defaultValue
-		}
-
-		if len(vs) > 0 {
-			val = vs[0]
-		}
-		return true, setWithProperType(val, value, field)
-	}
-}
-
-func setWithProperType(val string, value reflect.Value, field reflect.StructField) error {
-	switch value.Kind() {
-	case reflect.Int:
-		return setIntField(val, 0, value)
-	case reflect.Int8:
-		return setIntField(val, 8, value)
-	case reflect.Int16:
-		return setIntField(val, 16, value)
-	case reflect.Int32:
-		return setIntField(val, 32, value)
-	case reflect.Int64:
-		switch value.Interface().(type) {
-		case time.Duration:
-			return setTimeDuration(val, value, field)
-		}
-		return setIntField(val, 64, value)
-	case reflect.Uint:
-		return setUintField(val, 0, value)
-	case reflect.Uint8:
-		return setUintField(val, 8, value)
-	case reflect.Uint16:
-		return setUintField(val, 16, value)
-	case reflect.Uint32:
-		return setUintField(val, 32, value)
-	case reflect.Uint64:
-		return setUintField(val, 64, value)
-	case reflect.Bool:
-		return setBoolField(val, value)
-	case reflect.Float32:
-		return setFloatField(val, 32, value)
-	case reflect.Float64:
-		return setFloatField(val, 64, value)
-	case reflect.String:
-		value.SetString(val)
-	case reflect.Struct:
-		switch value.Interface().(type) {
-		case time.Time:
-			return setTimeField(val, field, value)
-		}
-		return json.Unmarshal([]byte(val), value.Addr().Interface())
-	case reflect.Map:
-		return json.Unmarshal([]byte(val), value.Addr().Interface())
-	default:
-		return errUnknownType
-	}
-	return nil
-}
-
-func setIntField(val string, bitSize int, field reflect.Value) error {
-	if val == "" {
-		val = "0"
-	}
-	intVal, err := strconv.ParseInt(val, 10, bitSize)
-	if err == nil {
-		field.SetInt(intVal)
-	}
-	return err
-}
-
-func setUintField(val string, bitSize int, field reflect.Value) error {
-	if val == "" {
-		val = "0"
-	}
-	uintVal, err := strconv.ParseUint(val, 10, bitSize)
-	if err == nil {
-		field.SetUint(uintVal)
-	}
-	return err
-}
-
-func setBoolField(val string, field reflect.Value) error {
-	if val == "" {
-		val = "false"
-	}
-	boolVal, err := strconv.ParseBool(val)
-	if err == nil {
-		field.SetBool(boolVal)
-	}
-	return err
-}
-
-func setFloatField(val string, bitSize int, field reflect.Value) error {
-	if val == "" {
-		val = "0.0"
-	}
-	floatVal, err := strconv.ParseFloat(val, bitSize)
-	if err == nil {
-		field.SetFloat(floatVal)
-	}
-	return err
-}
-
-func setTimeField(val string, structField reflect.StructField, value reflect.Value) error {
-	timeFormat := structField.Tag.Get("time_format")
-	if timeFormat == "" {
-		timeFormat = time.RFC3339
-	}
-
-	switch tf := strings.ToLower(timeFormat); tf {
-	case "unix", "unixnano":
-		tv, err := strconv.ParseInt(val, 10, 64)
-		if err != nil {
-			return err
-		}
-
-		d := time.Duration(1)
-		if tf == "unixnano" {
-			d = time.Second
-		}
-
-		t := time.Unix(tv/int64(d), tv%int64(d))
-		value.Set(reflect.ValueOf(t))
-		return nil
-
-	}
-
-	if val == "" {
-		value.Set(reflect.ValueOf(time.Time{}))
-		return nil
-	}
-
-	l := time.Local
-	if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC {
-		l = time.UTC
-	}
-
-	if locTag := structField.Tag.Get("time_location"); locTag != "" {
-		loc, err := time.LoadLocation(locTag)
-		if err != nil {
-			return err
-		}
-		l = loc
-	}
-
-	t, err := time.ParseInLocation(timeFormat, val, l)
-	if err != nil {
-		return err
-	}
-
-	value.Set(reflect.ValueOf(t))
-	return nil
-}
-
-func setArray(vals []string, value reflect.Value, field reflect.StructField) error {
-	for i, s := range vals {
-		err := setWithProperType(s, value.Index(i), field)
-		if err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-func setSlice(vals []string, value reflect.Value, field reflect.StructField) error {
-	slice := reflect.MakeSlice(value.Type(), len(vals), len(vals))
-	err := setArray(vals, slice, field)
-	if err != nil {
-		return err
-	}
-	value.Set(slice)
-	return nil
-}
-
-func setTimeDuration(val string, value reflect.Value, field reflect.StructField) error {
-	d, err := time.ParseDuration(val)
-	if err != nil {
-		return err
-	}
-	value.Set(reflect.ValueOf(d))
-	return nil
-}
-
-func head(str, sep string) (head string, tail string) {
-	idx := strings.Index(str, sep)
-	if idx < 0 {
-		return str, ""
-	}
-	return str[:idx], str[idx+len(sep):]
-}
-
-func setFormMap(ptr interface{}, form map[string][]string) error {
-	el := reflect.TypeOf(ptr).Elem()
-
-	if el.Kind() == reflect.Slice {
-		ptrMap, ok := ptr.(map[string][]string)
-		if !ok {
-			return errors.New("cannot convert to map slices of strings")
-		}
-		for k, v := range form {
-			ptrMap[k] = v
-		}
-
-		return nil
-	}
-
-	ptrMap, ok := ptr.(map[string]string)
-	if !ok {
-		return errors.New("cannot convert to map of strings")
-	}
-	for k, v := range form {
-		ptrMap[k] = v[len(v)-1] // pick last
-	}
-
-	return nil
-}


Test patch:
diff --git a/encoding/form/form_test.go b/encoding/form/form_test.go
index f7568d71..2022910a 100644
--- a/encoding/form/form_test.go
+++ b/encoding/form/form_test.go
@@ -1,9 +1,11 @@
 package form
 
 import (
+	"testing"
+
 	"github.com/go-kratos/kratos/v2/encoding"
+	"github.com/go-kratos/kratos/v2/internal/testproto/complex"
 	"github.com/stretchr/testify/require"
-	"testing"
 )
 
 type LoginRequest struct {
@@ -45,3 +47,26 @@ func TestFormCodecUnmarshal(t *testing.T) {
 	require.Equal(t, "kratos", bindReq.Username)
 	require.Equal(t, "kratos_pwd", bindReq.Password)
 }
+
+func TestProtoEncodeDecode(t *testing.T) {
+	in := &complex.Complex{
+		Id:      2233,
+		NoOne:   "2233",
+		Simple:  &complex.Simple{Component: "5566"},
+		Simples: []string{"3344", "5566"},
+	}
+	content, err := encoding.GetCodec(contentType).Marshal(in)
+	require.NoError(t, err)
+	require.Equal(t, "id=2233&numberOne=2233&simples=3344&simples=5566&very_simple.component=5566", string(content))
+	var in2 = &complex.Complex{}
+	err = encoding.GetCodec(contentType).Unmarshal(content, in2)
+	require.NoError(t, err)
+	require.Equal(t, int64(2233), in2.Id)
+	require.Equal(t, "2233", in2.NoOne)
+	require.NotEmpty(t, in2.Simple)
+	require.Equal(t, "5566", in2.Simple.Component)
+	require.NotEmpty(t, in2.Simples)
+	require.Len(t, in2.Simples, 2)
+	require.Equal(t, "3344", in2.Simples[0])
+	require.Equal(t, "5566", in2.Simples[1])
+}
diff --git a/internal/testproto/complex/complex.pb.go b/internal/testproto/complex/complex.pb.go
new file mode 100644
index 00000000..2e5fef62
--- /dev/null
+++ b/internal/testproto/complex/complex.pb.go
@@ -0,0 +1,242 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.27.1-devel
+// 	protoc        v3.17.2
+// source: complex.proto
+
+package complex
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// SimpleMessage represents a simple message sent to the Echo service.
+type Complex struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Id represents the message identifier.
+	Id      int64    `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+	NoOne   string   `protobuf:"bytes,2,opt,name=no_one,json=numberOne,proto3" json:"no_one,omitempty"`
+	Simple  *Simple  `protobuf:"bytes,3,opt,name=simple,json=very_simple,proto3" json:"simple,omitempty"`
+	Simples []string `protobuf:"bytes,4,rep,name=simples,proto3" json:"simples,omitempty"`
+}
+
+func (x *Complex) Reset() {
+	*x = Complex{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_complex_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Complex) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Complex) ProtoMessage() {}
+
+func (x *Complex) ProtoReflect() protoreflect.Message {
+	mi := &file_complex_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Complex.ProtoReflect.Descriptor instead.
+func (*Complex) Descriptor() ([]byte, []int) {
+	return file_complex_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Complex) GetId() int64 {
+	if x != nil {
+		return x.Id
+	}
+	return 0
+}
+
+func (x *Complex) GetNoOne() string {
+	if x != nil {
+		return x.NoOne
+	}
+	return ""
+}
+
+func (x *Complex) GetSimple() *Simple {
+	if x != nil {
+		return x.Simple
+	}
+	return nil
+}
+
+func (x *Complex) GetSimples() []string {
+	if x != nil {
+		return x.Simples
+	}
+	return nil
+}
+
+type Simple struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Component string `protobuf:"bytes,1,opt,name=component,proto3" json:"component,omitempty"`
+}
+
+func (x *Simple) Reset() {
+	*x = Simple{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_complex_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Simple) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Simple) ProtoMessage() {}
+
+func (x *Simple) ProtoReflect() protoreflect.Message {
+	mi := &file_complex_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Simple.ProtoReflect.Descriptor instead.
+func (*Simple) Descriptor() ([]byte, []int) {
+	return file_complex_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *Simple) GetComponent() string {
+	if x != nil {
+		return x.Component
+	}
+	return ""
+}
+
+var File_complex_proto protoreflect.FileDescriptor
+
+var file_complex_proto_rawDesc = []byte{
+	0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
+	0x09, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x7e, 0x0a, 0x07, 0x43, 0x6f,
+	0x6d, 0x70, 0x6c, 0x65, 0x78, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x06, 0x6e, 0x6f, 0x5f, 0x6f, 0x6e, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x4f, 0x6e, 0x65,
+	0x12, 0x2e, 0x0a, 0x06, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x11, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d,
+	0x70, 0x6c, 0x65, 0x52, 0x0b, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65,
+	0x12, 0x18, 0x0a, 0x07, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28,
+	0x09, 0x52, 0x07, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x22, 0x26, 0x0a, 0x06, 0x53, 0x69,
+	0x6d, 0x70, 0x6c, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e,
+	0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65,
+	0x6e, 0x74, 0x42, 0x58, 0x5a, 0x56, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
+	0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x6b, 0x72, 0x61, 0x74, 0x6f,
+	0x73, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e,
+	0x2d, 0x67, 0x6f, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
+	0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x70,
+	0x6c, 0x65, 0x78, 0x2f, 0x3b, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x62, 0x06, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_complex_proto_rawDescOnce sync.Once
+	file_complex_proto_rawDescData = file_complex_proto_rawDesc
+)
+
+func file_complex_proto_rawDescGZIP() []byte {
+	file_complex_proto_rawDescOnce.Do(func() {
+		file_complex_proto_rawDescData = protoimpl.X.CompressGZIP(file_complex_proto_rawDescData)
+	})
+	return file_complex_proto_rawDescData
+}
+
+var file_complex_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_complex_proto_goTypes = []interface{}{
+	(*Complex)(nil), // 0: testproto.Complex
+	(*Simple)(nil),  // 1: testproto.Simple
+}
+var file_complex_proto_depIdxs = []int32{
+	1, // 0: testproto.Complex.simple:type_name -> testproto.Simple
+	1, // [1:1] is the sub-list for method output_type
+	1, // [1:1] is the sub-list for method input_type
+	1, // [1:1] is the sub-list for extension type_name
+	1, // [1:1] is the sub-list for extension extendee
+	0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_complex_proto_init() }
+func file_complex_proto_init() {
+	if File_complex_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_complex_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Complex); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_complex_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Simple); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_complex_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_complex_proto_goTypes,
+		DependencyIndexes: file_complex_proto_depIdxs,
+		MessageInfos:      file_complex_proto_msgTypes,
+	}.Build()
+	File_complex_proto = out.File
+	file_complex_proto_rawDesc = nil
+	file_complex_proto_goTypes = nil
+	file_complex_proto_depIdxs = nil
+}
diff --git a/internal/testproto/complex/complex.proto b/internal/testproto/complex/complex.proto
new file mode 100644
index 00000000..5a7c951a
--- /dev/null
+++ b/internal/testproto/complex/complex.proto
@@ -0,0 +1,19 @@
+syntax = "proto3";
+
+option go_package = "github.com/go-kratos/kratos/cmd/protoc-gen-go-http/internal/testproto/complex/;complex";
+
+package testproto;
+
+
+// SimpleMessage represents a simple message sent to the Echo service.
+message Complex {
+	// Id represents the message identifier.
+	int64 id = 1;
+    string no_one = 2 [json_name="numberOne"];
+    Simple simple = 3 [json_name="very_simple"];
+    repeated string simples = 4;
+}
+
+message Simple {
+    string component = 1;
+}
\ No newline at end of file
diff --git a/internal/testproto/echo_service.pb.go b/internal/testproto/echo/echo_service.pb.go
similarity index 57%
rename from internal/testproto/echo_service.pb.go
rename to internal/testproto/echo/echo_service.pb.go
index 0ffaac82..45da34a2 100644
--- a/internal/testproto/echo_service.pb.go
+++ b/internal/testproto/echo/echo_service.pb.go
@@ -1,10 +1,10 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.26.0
-// 	protoc        v3.17.3
+// 	protoc-gen-go v1.27.1-devel
+// 	protoc        v3.17.2
 // source: echo_service.proto
 
-package testproto
+package echo
 
 import (
 	_ "google.golang.org/genproto/googleapis/api/annotations"
@@ -173,7 +173,7 @@ type SimpleMessage struct {
 
 	// Id represents the message identifier.
 	Id  string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
-	Num int64  `protobuf:"varint,2,opt,name=num,proto3" json:"num,omitempty"`
+	Num int64  `protobuf:"varint,2,opt,name=num,json=number,proto3" json:"num,omitempty"`
 	// Types that are assignable to Code:
 	//	*SimpleMessage_LineNum
 	//	*SimpleMessage_Lang
@@ -183,7 +183,7 @@ type SimpleMessage struct {
 	//	*SimpleMessage_En
 	//	*SimpleMessage_No
 	Ext    isSimpleMessage_Ext `protobuf_oneof:"ext"`
-	Corpus Corpus              `protobuf:"varint,8,opt,name=corpus,proto3,enum=testproto.Corpus" json:"corpus,omitempty"`
+	Corpus Corpus              `protobuf:"varint,8,opt,name=corpus,proto3,enum=echo.Corpus" json:"corpus,omitempty"`
 }
 
 func (x *SimpleMessage) Reset() {
@@ -436,108 +436,103 @@ var File_echo_service_proto protoreflect.FileDescriptor
 
 var file_echo_service_proto_rawDesc = []byte{
 	0x0a, 0x12, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
-	0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f,
-	0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67,
-	0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66,
-	0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
-	0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
-	0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x46, 0x0a,
-	0x08, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, 0x72, 0x6f,
-	0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x70,
-	0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, 0x06, 0x0a,
-	0x04, 0x6d, 0x61, 0x72, 0x6b, 0x22, 0x84, 0x02, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65,
-	0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02,
-	0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6e, 0x75, 0x6d, 0x12, 0x1b, 0x0a, 0x08, 0x6c, 0x69, 0x6e,
-	0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x07, 0x6c,
-	0x69, 0x6e, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x18, 0x04,
-	0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x2b, 0x0a, 0x06,
-	0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74,
-	0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65,
-	0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x02, 0x65, 0x6e, 0x18,
-	0x06, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x02, 0x65, 0x6e, 0x12, 0x25, 0x0a, 0x02, 0x6e,
-	0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72,
-	0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x48, 0x01, 0x52, 0x02,
-	0x6e, 0x6f, 0x12, 0x29, 0x0a, 0x06, 0x63, 0x6f, 0x72, 0x70, 0x75, 0x73, 0x18, 0x08, 0x20, 0x01,
-	0x28, 0x0e, 0x32, 0x11, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43,
-	0x6f, 0x72, 0x70, 0x75, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x72, 0x70, 0x75, 0x73, 0x42, 0x06, 0x0a,
-	0x04, 0x63, 0x6f, 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x65, 0x78, 0x74, 0x22, 0x85, 0x01, 0x0a,
-	0x0e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
-	0x3a, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0b,
-	0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x37, 0x0a, 0x0b, 0x76,
-	0x61, 0x6c, 0x75, 0x65, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
-	0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
-	0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x46,
-	0x69, 0x65, 0x6c, 0x64, 0x22, 0x82, 0x01, 0x0a, 0x14, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63,
-	0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x2d, 0x0a,
-	0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x65,
-	0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d,
-	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x3b, 0x0a, 0x0b,
-	0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28,
-	0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75,
-	0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x2a, 0x5a, 0x0a, 0x06, 0x43, 0x6f, 0x72,
-	0x70, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x49, 0x56, 0x45, 0x52, 0x53, 0x41, 0x4c,
-	0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x57, 0x45, 0x42, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x49,
-	0x4d, 0x41, 0x47, 0x45, 0x53, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x4f, 0x43, 0x41, 0x4c,
-	0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x45, 0x57, 0x53, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08,
-	0x50, 0x52, 0x4f, 0x44, 0x55, 0x43, 0x54, 0x53, 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x56, 0x49,
-	0x44, 0x45, 0x4f, 0x10, 0x06, 0x32, 0xcf, 0x05, 0x0a, 0x0b, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65,
-	0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xf2, 0x01, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x18,
-	0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c,
-	0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x18, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61,
-	0x67, 0x65, 0x22, 0xb5, 0x01, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0xae, 0x01, 0x22, 0x15, 0x2f, 0x76,
-	0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b,
-	0x69, 0x64, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70,
-	0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75,
-	0x6d, 0x7d, 0x5a, 0x24, 0x12, 0x22, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c,
+	0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x65, 0x63, 0x68, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67,
+	0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f,
+	0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+	0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f,
+	0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67,
+	0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75,
+	0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x46, 0x0a, 0x08, 0x45, 0x6d, 0x62, 0x65,
+	0x64, 0x64, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65,
+	0x73, 0x73, 0x12, 0x14, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x48, 0x00, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b,
+	0x22, 0xf8, 0x01, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61,
+	0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02,
+	0x69, 0x64, 0x12, 0x13, 0x0a, 0x03, 0x6e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52,
+	0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x08, 0x6c, 0x69, 0x6e, 0x65, 0x5f,
+	0x6e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x07, 0x6c, 0x69, 0x6e,
+	0x65, 0x4e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01,
+	0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x61, 0x6e, 0x67, 0x12, 0x26, 0x0a, 0x06, 0x73, 0x74,
+	0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x65, 0x63, 0x68,
+	0x6f, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74,
+	0x75, 0x73, 0x12, 0x10, 0x0a, 0x02, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01,
+	0x52, 0x02, 0x65, 0x6e, 0x12, 0x20, 0x0a, 0x02, 0x6e, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x0e, 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64,
+	0x48, 0x01, 0x52, 0x02, 0x6e, 0x6f, 0x12, 0x24, 0x0a, 0x06, 0x63, 0x6f, 0x72, 0x70, 0x75, 0x73,
+	0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x43, 0x6f,
+	0x72, 0x70, 0x75, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x72, 0x70, 0x75, 0x73, 0x42, 0x06, 0x0a, 0x04,
+	0x63, 0x6f, 0x64, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x65, 0x78, 0x74, 0x22, 0x85, 0x01, 0x0a, 0x0e,
+	0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3a,
+	0x0a, 0x0c, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0b, 0x73,
+	0x74, 0x72, 0x75, 0x63, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x37, 0x0a, 0x0b, 0x76, 0x61,
+	0x6c, 0x75, 0x65, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
+	0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x46, 0x69,
+	0x65, 0x6c, 0x64, 0x22, 0x7d, 0x0a, 0x14, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65,
+	0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x04, 0x62,
+	0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x65, 0x63, 0x68, 0x6f,
+	0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52,
+	0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f,
+	0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
+	0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65,
+	0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61,
+	0x73, 0x6b, 0x2a, 0x5a, 0x0a, 0x06, 0x43, 0x6f, 0x72, 0x70, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09,
+	0x55, 0x4e, 0x49, 0x56, 0x45, 0x52, 0x53, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x57,
+	0x45, 0x42, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x53, 0x10, 0x02,
+	0x12, 0x09, 0x0a, 0x05, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x4e,
+	0x45, 0x57, 0x53, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x52, 0x4f, 0x44, 0x55, 0x43, 0x54,
+	0x53, 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x56, 0x49, 0x44, 0x45, 0x4f, 0x10, 0x06, 0x32, 0x9c,
+	0x05, 0x0a, 0x0b, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xe8,
+	0x01, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x13, 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x53,
+	0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x13, 0x2e, 0x65,
+	0x63, 0x68, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
+	0x65, 0x22, 0xb5, 0x01, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0xae, 0x01, 0x22, 0x15, 0x2f, 0x76, 0x31,
+	0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69,
+	0x64, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c,
 	0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d,
-	0x7d, 0x2f, 0x7b, 0x6c, 0x61, 0x6e, 0x67, 0x7d, 0x5a, 0x31, 0x12, 0x2f, 0x2f, 0x76, 0x31, 0x2f,
-	0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x31, 0x2f, 0x7b, 0x69,
-	0x64, 0x7d, 0x2f, 0x7b, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x73,
-	0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f,
-	0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x32,
-	0x2f, 0x7b, 0x6e, 0x6f, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x7d, 0x12, 0x60, 0x0a, 0x08, 0x45, 0x63,
-	0x68, 0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x18, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
-	0x1a, 0x18, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d,
-	0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93,
-	0x02, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f,
-	0x65, 0x63, 0x68, 0x6f, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0x85, 0x01, 0x0a,
-	0x10, 0x45, 0x63, 0x68, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x6f, 0x64,
-	0x79, 0x12, 0x1f, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x79,
-	0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61,
-	0x74, 0x65, 0x1a, 0x1f, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44,
-	0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64,
-	0x61, 0x74, 0x65, 0x22, 0x2f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x29, 0x22, 0x1e, 0x2f, 0x76, 0x31,
-	0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x72, 0x65,
-	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x3a, 0x01, 0x2a, 0x62, 0x04,
-	0x62, 0x6f, 0x64, 0x79, 0x12, 0x6c, 0x0a, 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65,
-	0x74, 0x65, 0x12, 0x18, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53,
-	0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x18, 0x2e, 0x74,
-	0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d,
+	0x7d, 0x5a, 0x24, 0x12, 0x22, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
+	0x2f, 0x65, 0x63, 0x68, 0x6f, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d,
+	0x2f, 0x7b, 0x6c, 0x61, 0x6e, 0x67, 0x7d, 0x5a, 0x31, 0x12, 0x2f, 0x2f, 0x76, 0x31, 0x2f, 0x65,
+	0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x31, 0x2f, 0x7b, 0x69, 0x64,
+	0x7d, 0x2f, 0x7b, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x7d, 0x2f, 0x7b, 0x73, 0x74,
+	0x61, 0x74, 0x75, 0x73, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x7d, 0x5a, 0x1d, 0x12, 0x1b, 0x2f, 0x76,
+	0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x32, 0x2f,
+	0x7b, 0x6e, 0x6f, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x7d, 0x12, 0x56, 0x0a, 0x08, 0x45, 0x63, 0x68,
+	0x6f, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x13, 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x53, 0x69, 0x6d,
+	0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x13, 0x2e, 0x65, 0x63, 0x68,
+	0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22,
+	0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61,
+	0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x3a, 0x01,
+	0x2a, 0x12, 0x7b, 0x0a, 0x10, 0x45, 0x63, 0x68, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x1a, 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x44, 0x79, 0x6e,
+	0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74,
+	0x65, 0x1a, 0x1a, 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63,
+	0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x2f, 0x82,
+	0xd3, 0xe4, 0x93, 0x02, 0x29, 0x22, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70,
+	0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x5f, 0x62, 0x6f, 0x64, 0x79, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x62,
+	0x0a, 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x65,
+	0x63, 0x68, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
+	0x65, 0x1a, 0x13, 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d,
 	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x2a, 0x22,
 	0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f,
 	0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75,
-	0x6d, 0x7d, 0x12, 0x73, 0x0a, 0x09, 0x45, 0x63, 0x68, 0x6f, 0x50, 0x61, 0x74, 0x63, 0x68, 0x12,
-	0x1f, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x79, 0x6e, 0x61,
-	0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
-	0x1a, 0x1f, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x79, 0x6e,
-	0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74,
-	0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x32, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x65,
-	0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x70, 0x61, 0x74, 0x63,
-	0x68, 0x3a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x51, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75,
-	0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f,
-	0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x69, 0x6e,
-	0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x3b, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
-	0x6f, 0x33,
+	0x6d, 0x7d, 0x12, 0x69, 0x0a, 0x09, 0x45, 0x63, 0x68, 0x6f, 0x50, 0x61, 0x74, 0x63, 0x68, 0x12,
+	0x1a, 0x2e, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65,
+	0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x1a, 0x2e, 0x65, 0x63,
+	0x68, 0x6f, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
+	0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x32,
+	0x16, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68,
+	0x6f, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x3a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x51, 0x5a,
+	0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b,
+	0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x63, 0x6d, 0x64,
+	0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x68,
+	0x74, 0x74, 0x70, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x73,
+	0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x3b, 0x65, 0x63, 0x68, 0x6f,
+	0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -555,33 +550,33 @@ func file_echo_service_proto_rawDescGZIP() []byte {
 var file_echo_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
 var file_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
 var file_echo_service_proto_goTypes = []interface{}{
-	(Corpus)(0),                   // 0: testproto.Corpus
-	(*Embedded)(nil),              // 1: testproto.Embedded
-	(*SimpleMessage)(nil),         // 2: testproto.SimpleMessage
-	(*DynamicMessage)(nil),        // 3: testproto.DynamicMessage
-	(*DynamicMessageUpdate)(nil),  // 4: testproto.DynamicMessageUpdate
+	(Corpus)(0),                   // 0: echo.Corpus
+	(*Embedded)(nil),              // 1: echo.Embedded
+	(*SimpleMessage)(nil),         // 2: echo.SimpleMessage
+	(*DynamicMessage)(nil),        // 3: echo.DynamicMessage
+	(*DynamicMessageUpdate)(nil),  // 4: echo.DynamicMessageUpdate
 	(*structpb.Struct)(nil),       // 5: google.protobuf.Struct
 	(*structpb.Value)(nil),        // 6: google.protobuf.Value
 	(*fieldmaskpb.FieldMask)(nil), // 7: google.protobuf.FieldMask
 }
 var file_echo_service_proto_depIdxs = []int32{
-	1,  // 0: testproto.SimpleMessage.status:type_name -> testproto.Embedded
-	1,  // 1: testproto.SimpleMessage.no:type_name -> testproto.Embedded
-	0,  // 2: testproto.SimpleMessage.corpus:type_name -> testproto.Corpus
-	5,  // 3: testproto.DynamicMessage.struct_field:type_name -> google.protobuf.Struct
-	6,  // 4: testproto.DynamicMessage.value_field:type_name -> google.protobuf.Value
-	3,  // 5: testproto.DynamicMessageUpdate.body:type_name -> testproto.DynamicMessage
-	7,  // 6: testproto.DynamicMessageUpdate.update_mask:type_name -> google.protobuf.FieldMask
-	2,  // 7: testproto.EchoService.Echo:input_type -> testproto.SimpleMessage
-	2,  // 8: testproto.EchoService.EchoBody:input_type -> testproto.SimpleMessage
-	4,  // 9: testproto.EchoService.EchoResponseBody:input_type -> testproto.DynamicMessageUpdate
-	2,  // 10: testproto.EchoService.EchoDelete:input_type -> testproto.SimpleMessage
-	4,  // 11: testproto.EchoService.EchoPatch:input_type -> testproto.DynamicMessageUpdate
-	2,  // 12: testproto.EchoService.Echo:output_type -> testproto.SimpleMessage
-	2,  // 13: testproto.EchoService.EchoBody:output_type -> testproto.SimpleMessage
-	4,  // 14: testproto.EchoService.EchoResponseBody:output_type -> testproto.DynamicMessageUpdate
-	2,  // 15: testproto.EchoService.EchoDelete:output_type -> testproto.SimpleMessage
-	4,  // 16: testproto.EchoService.EchoPatch:output_type -> testproto.DynamicMessageUpdate
+	1,  // 0: echo.SimpleMessage.status:type_name -> echo.Embedded
+	1,  // 1: echo.SimpleMessage.no:type_name -> echo.Embedded
+	0,  // 2: echo.SimpleMessage.corpus:type_name -> echo.Corpus
+	5,  // 3: echo.DynamicMessage.struct_field:type_name -> google.protobuf.Struct
+	6,  // 4: echo.DynamicMessage.value_field:type_name -> google.protobuf.Value
+	3,  // 5: echo.DynamicMessageUpdate.body:type_name -> echo.DynamicMessage
+	7,  // 6: echo.DynamicMessageUpdate.update_mask:type_name -> google.protobuf.FieldMask
+	2,  // 7: echo.EchoService.Echo:input_type -> echo.SimpleMessage
+	2,  // 8: echo.EchoService.EchoBody:input_type -> echo.SimpleMessage
+	4,  // 9: echo.EchoService.EchoResponseBody:input_type -> echo.DynamicMessageUpdate
+	2,  // 10: echo.EchoService.EchoDelete:input_type -> echo.SimpleMessage
+	4,  // 11: echo.EchoService.EchoPatch:input_type -> echo.DynamicMessageUpdate
+	2,  // 12: echo.EchoService.Echo:output_type -> echo.SimpleMessage
+	2,  // 13: echo.EchoService.EchoBody:output_type -> echo.SimpleMessage
+	4,  // 14: echo.EchoService.EchoResponseBody:output_type -> echo.DynamicMessageUpdate
+	2,  // 15: echo.EchoService.EchoDelete:output_type -> echo.SimpleMessage
+	4,  // 16: echo.EchoService.EchoPatch:output_type -> echo.DynamicMessageUpdate
 	12, // [12:17] is the sub-list for method output_type
 	7,  // [7:12] is the sub-list for method input_type
 	7,  // [7:7] is the sub-list for extension type_name
diff --git a/internal/testproto/echo_service.proto b/internal/testproto/echo/echo_service.proto
similarity index 96%
rename from internal/testproto/echo_service.proto
rename to internal/testproto/echo/echo_service.proto
index ed084156..c62a533b 100644
--- a/internal/testproto/echo_service.proto
+++ b/internal/testproto/echo/echo_service.proto
@@ -1,8 +1,8 @@
 syntax = "proto3";
 
-option go_package = "github.com/go-kratos/kratos/cmd/protoc-gen-go-http/internal/testproto;testproto";
+package echo;
 
-package testproto;
+option go_package = "github.com/go-kratos/kratos/cmd/protoc-gen-go-http/internal/testproto/echo;echo";
 
 import "google/api/annotations.proto";
 import "google/protobuf/field_mask.proto";
@@ -30,7 +30,7 @@ message Embedded {
 message SimpleMessage {
 	// Id represents the message identifier.
 	string id = 1;
-	int64 num = 2;
+	int64 num = 2 [json_name="number"];
 	oneof code {
 		int64 line_num = 3;
 		string lang = 4;
diff --git a/internal/testproto/echo_service_grpc.pb.go b/internal/testproto/echo/echo_service_grpc.pb.go
similarity index 93%
rename from internal/testproto/echo_service_grpc.pb.go
rename to internal/testproto/echo/echo_service_grpc.pb.go
index 23374bdc..af8386b9 100644
--- a/internal/testproto/echo_service_grpc.pb.go
+++ b/internal/testproto/echo/echo_service_grpc.pb.go
@@ -1,6 +1,6 @@
 // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 
-package testproto
+package echo
 
 import (
 	context "context"
@@ -43,7 +43,7 @@ func NewEchoServiceClient(cc grpc.ClientConnInterface) EchoServiceClient {
 
 func (c *echoServiceClient) Echo(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) {
 	out := new(SimpleMessage)
-	err := c.cc.Invoke(ctx, "/testproto.EchoService/Echo", in, out, opts...)
+	err := c.cc.Invoke(ctx, "/echo.EchoService/Echo", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -52,7 +52,7 @@ func (c *echoServiceClient) Echo(ctx context.Context, in *SimpleMessage, opts ..
 
 func (c *echoServiceClient) EchoBody(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) {
 	out := new(SimpleMessage)
-	err := c.cc.Invoke(ctx, "/testproto.EchoService/EchoBody", in, out, opts...)
+	err := c.cc.Invoke(ctx, "/echo.EchoService/EchoBody", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -61,7 +61,7 @@ func (c *echoServiceClient) EchoBody(ctx context.Context, in *SimpleMessage, opt
 
 func (c *echoServiceClient) EchoResponseBody(ctx context.Context, in *DynamicMessageUpdate, opts ...grpc.CallOption) (*DynamicMessageUpdate, error) {
 	out := new(DynamicMessageUpdate)
-	err := c.cc.Invoke(ctx, "/testproto.EchoService/EchoResponseBody", in, out, opts...)
+	err := c.cc.Invoke(ctx, "/echo.EchoService/EchoResponseBody", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -70,7 +70,7 @@ func (c *echoServiceClient) EchoResponseBody(ctx context.Context, in *DynamicMes
 
 func (c *echoServiceClient) EchoDelete(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) {
 	out := new(SimpleMessage)
-	err := c.cc.Invoke(ctx, "/testproto.EchoService/EchoDelete", in, out, opts...)
+	err := c.cc.Invoke(ctx, "/echo.EchoService/EchoDelete", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -79,7 +79,7 @@ func (c *echoServiceClient) EchoDelete(ctx context.Context, in *SimpleMessage, o
 
 func (c *echoServiceClient) EchoPatch(ctx context.Context, in *DynamicMessageUpdate, opts ...grpc.CallOption) (*DynamicMessageUpdate, error) {
 	out := new(DynamicMessageUpdate)
-	err := c.cc.Invoke(ctx, "/testproto.EchoService/EchoPatch", in, out, opts...)
+	err := c.cc.Invoke(ctx, "/echo.EchoService/EchoPatch", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -148,7 +148,7 @@ func _EchoService_Echo_Handler(srv interface{}, ctx context.Context, dec func(in
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/testproto.EchoService/Echo",
+		FullMethod: "/echo.EchoService/Echo",
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(EchoServiceServer).Echo(ctx, req.(*SimpleMessage))
@@ -166,7 +166,7 @@ func _EchoService_EchoBody_Handler(srv interface{}, ctx context.Context, dec fun
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/testproto.EchoService/EchoBody",
+		FullMethod: "/echo.EchoService/EchoBody",
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(EchoServiceServer).EchoBody(ctx, req.(*SimpleMessage))
@@ -184,7 +184,7 @@ func _EchoService_EchoResponseBody_Handler(srv interface{}, ctx context.Context,
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/testproto.EchoService/EchoResponseBody",
+		FullMethod: "/echo.EchoService/EchoResponseBody",
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(EchoServiceServer).EchoResponseBody(ctx, req.(*DynamicMessageUpdate))
@@ -202,7 +202,7 @@ func _EchoService_EchoDelete_Handler(srv interface{}, ctx context.Context, dec f
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/testproto.EchoService/EchoDelete",
+		FullMethod: "/echo.EchoService/EchoDelete",
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(EchoServiceServer).EchoDelete(ctx, req.(*SimpleMessage))
@@ -220,7 +220,7 @@ func _EchoService_EchoPatch_Handler(srv interface{}, ctx context.Context, dec fu
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/testproto.EchoService/EchoPatch",
+		FullMethod: "/echo.EchoService/EchoPatch",
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(EchoServiceServer).EchoPatch(ctx, req.(*DynamicMessageUpdate))
@@ -232,7 +232,7 @@ func _EchoService_EchoPatch_Handler(srv interface{}, ctx context.Context, dec fu
 // It's only intended for direct use with grpc.RegisterService,
 // and not to be introspected or modified (even as a copy)
 var EchoService_ServiceDesc = grpc.ServiceDesc{
-	ServiceName: "testproto.EchoService",
+	ServiceName: "echo.EchoService",
 	HandlerType: (*EchoServiceServer)(nil),
 	Methods: []grpc.MethodDesc{
 		{
diff --git a/internal/testproto/echo_service_http.pb.go b/internal/testproto/echo/echo_service_http.pb.go
similarity index 91%
rename from internal/testproto/echo_service_http.pb.go
rename to internal/testproto/echo/echo_service_http.pb.go
index 7500dbfb..253d1180 100644
--- a/internal/testproto/echo_service_http.pb.go
+++ b/internal/testproto/echo/echo_service_http.pb.go
@@ -2,7 +2,7 @@
 // versions:
 // protoc-gen-go-http v2.0.0-rc7
 
-package testproto
+package echo
 
 import (
 	context "context"
@@ -47,7 +47,7 @@ func _EchoService_Echo0_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Co
 		if err := ctx.BindVars(&in); err != nil {
 			return err
 		}
-		http.SetOperation(ctx, "/testproto.EchoService/Echo")
+		http.SetOperation(ctx, "/echo.EchoService/Echo")
 		h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
 			return srv.Echo(ctx, req.(*SimpleMessage))
 		})
@@ -69,7 +69,7 @@ func _EchoService_Echo1_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Co
 		if err := ctx.BindVars(&in); err != nil {
 			return err
 		}
-		http.SetOperation(ctx, "/testproto.EchoService/Echo")
+		http.SetOperation(ctx, "/echo.EchoService/Echo")
 		h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
 			return srv.Echo(ctx, req.(*SimpleMessage))
 		})
@@ -91,7 +91,7 @@ func _EchoService_Echo2_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Co
 		if err := ctx.BindVars(&in); err != nil {
 			return err
 		}
-		http.SetOperation(ctx, "/testproto.EchoService/Echo")
+		http.SetOperation(ctx, "/echo.EchoService/Echo")
 		h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
 			return srv.Echo(ctx, req.(*SimpleMessage))
 		})
@@ -113,7 +113,7 @@ func _EchoService_Echo3_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Co
 		if err := ctx.BindVars(&in); err != nil {
 			return err
 		}
-		http.SetOperation(ctx, "/testproto.EchoService/Echo")
+		http.SetOperation(ctx, "/echo.EchoService/Echo")
 		h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
 			return srv.Echo(ctx, req.(*SimpleMessage))
 		})
@@ -135,7 +135,7 @@ func _EchoService_Echo4_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx http.Co
 		if err := ctx.BindVars(&in); err != nil {
 			return err
 		}
-		http.SetOperation(ctx, "/testproto.EchoService/Echo")
+		http.SetOperation(ctx, "/echo.EchoService/Echo")
 		h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
 			return srv.Echo(ctx, req.(*SimpleMessage))
 		})
@@ -154,7 +154,7 @@ func _EchoService_EchoBody0_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx htt
 		if err := ctx.Bind(&in); err != nil {
 			return err
 		}
-		http.SetOperation(ctx, "/testproto.EchoService/EchoBody")
+		http.SetOperation(ctx, "/echo.EchoService/EchoBody")
 		h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
 			return srv.EchoBody(ctx, req.(*SimpleMessage))
 		})
@@ -173,7 +173,7 @@ func _EchoService_EchoResponseBody0_HTTP_Handler(srv EchoServiceHTTPServer) func
 		if err := ctx.Bind(&in); err != nil {
 			return err
 		}
-		http.SetOperation(ctx, "/testproto.EchoService/EchoResponseBody")
+		http.SetOperation(ctx, "/echo.EchoService/EchoResponseBody")
 		h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
 			return srv.EchoResponseBody(ctx, req.(*DynamicMessageUpdate))
 		})
@@ -195,7 +195,7 @@ func _EchoService_EchoDelete0_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx h
 		if err := ctx.BindVars(&in); err != nil {
 			return err
 		}
-		http.SetOperation(ctx, "/testproto.EchoService/EchoDelete")
+		http.SetOperation(ctx, "/echo.EchoService/EchoDelete")
 		h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
 			return srv.EchoDelete(ctx, req.(*SimpleMessage))
 		})
@@ -214,7 +214,7 @@ func _EchoService_EchoPatch0_HTTP_Handler(srv EchoServiceHTTPServer) func(ctx ht
 		if err := ctx.Bind(&in.Body); err != nil {
 			return err
 		}
-		http.SetOperation(ctx, "/testproto.EchoService/EchoPatch")
+		http.SetOperation(ctx, "/echo.EchoService/EchoPatch")
 		h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
 			return srv.EchoPatch(ctx, req.(*DynamicMessageUpdate))
 		})
@@ -247,7 +247,7 @@ func (c *EchoServiceHTTPClientImpl) Echo(ctx context.Context, in *SimpleMessage,
 	var out SimpleMessage
 	pattern := "/v1/example/echo/{id}"
 	path := binding.EncodeURL(pattern, in, true)
-	opts = append(opts, http.Operation("/testproto.EchoService/Echo"))
+	opts = append(opts, http.Operation("/echo.EchoService/Echo"))
 	opts = append(opts, http.PathTemplate(pattern))
 	err := c.cc.Invoke(ctx, "POST", path, nil, &out, opts...)
 	if err != nil {
@@ -260,7 +260,7 @@ func (c *EchoServiceHTTPClientImpl) EchoBody(ctx context.Context, in *SimpleMess
 	var out SimpleMessage
 	pattern := "/v1/example/echo_body"
 	path := binding.EncodeURL(pattern, in, false)
-	opts = append(opts, http.Operation("/testproto.EchoService/EchoBody"))
+	opts = append(opts, http.Operation("/echo.EchoService/EchoBody"))
 	opts = append(opts, http.PathTemplate(pattern))
 	err := c.cc.Invoke(ctx, "POST", path, in, &out, opts...)
 	if err != nil {
@@ -273,7 +273,7 @@ func (c *EchoServiceHTTPClientImpl) EchoDelete(ctx context.Context, in *SimpleMe
 	var out SimpleMessage
 	pattern := "/v1/example/echo_delete/{id}/{num}"
 	path := binding.EncodeURL(pattern, in, true)
-	opts = append(opts, http.Operation("/testproto.EchoService/EchoDelete"))
+	opts = append(opts, http.Operation("/echo.EchoService/EchoDelete"))
 	opts = append(opts, http.PathTemplate(pattern))
 	err := c.cc.Invoke(ctx, "DELETE", path, nil, &out, opts...)
 	if err != nil {
@@ -286,7 +286,7 @@ func (c *EchoServiceHTTPClientImpl) EchoPatch(ctx context.Context, in *DynamicMe
 	var out DynamicMessageUpdate
 	pattern := "/v1/example/echo_patch"
 	path := binding.EncodeURL(pattern, in, false)
-	opts = append(opts, http.Operation("/testproto.EchoService/EchoPatch"))
+	opts = append(opts, http.Operation("/echo.EchoService/EchoPatch"))
 	opts = append(opts, http.PathTemplate(pattern))
 	err := c.cc.Invoke(ctx, "PATCH", path, in.Body, &out, opts...)
 	if err != nil {
@@ -299,7 +299,7 @@ func (c *EchoServiceHTTPClientImpl) EchoResponseBody(ctx context.Context, in *Dy
 	var out DynamicMessageUpdate
 	pattern := "/v1/example/echo_response_body"
 	path := binding.EncodeURL(pattern, in, false)
-	opts = append(opts, http.Operation("/testproto.EchoService/EchoResponseBody"))
+	opts = append(opts, http.Operation("/echo.EchoService/EchoResponseBody"))
 	opts = append(opts, http.PathTemplate(pattern))
 	err := c.cc.Invoke(ctx, "POST", path, in, &out.Body, opts...)
 	if err != nil {
diff --git a/internal/testproto/echo_service_test.go b/internal/testproto/echo/echo_service_test.go
similarity index 99%
rename from internal/testproto/echo_service_test.go
rename to internal/testproto/echo/echo_service_test.go
index 997291e5..9b0ffe49 100644
--- a/internal/testproto/echo_service_test.go
+++ b/internal/testproto/echo/echo_service_test.go
@@ -1,4 +1,4 @@
-package testproto
+package echo
 
 import (
 	context "context"
diff --git a/internal/testproto/generate.go b/internal/testproto/echo/generate.go
similarity index 92%
rename from internal/testproto/generate.go
rename to internal/testproto/echo/generate.go
index c0c47a75..5f0697a0 100644
--- a/internal/testproto/generate.go
+++ b/internal/testproto/echo/generate.go
@@ -1,3 +1,3 @@
-package testproto
+package echo
 
 //go:generate protoc --proto_path=. --proto_path=../../third_party --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:. --go-http_out=paths=source_relative:. echo_service.proto stream.proto
diff --git a/internal/testproto/echo/stream.pb.go b/internal/testproto/echo/stream.pb.go
new file mode 100644
index 00000000..da3d7659
--- /dev/null
+++ b/internal/testproto/echo/stream.pb.go
@@ -0,0 +1,85 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.27.1-devel
+// 	protoc        v3.17.2
+// source: stream.proto
+
+package echo
+
+import (
+	_ "google.golang.org/genproto/googleapis/api/annotations"
+	httpbody "google.golang.org/genproto/googleapis/api/httpbody"
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	emptypb "google.golang.org/protobuf/types/known/emptypb"
+	reflect "reflect"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+var File_stream_proto protoreflect.FileDescriptor
+
+var file_stream_proto_rawDesc = []byte{
+	0x0a, 0x0c, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04,
+	0x65, 0x63, 0x68, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69,
+	0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x68,
+	0x74, 0x74, 0x70, 0x62, 0x6f, 0x64, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67,
+	0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65,
+	0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0x69, 0x0a, 0x0d, 0x53, 0x74,
+	0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x08, 0x44,
+	0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a,
+	0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, 0x74, 0x74,
+	0x70, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f,
+	0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x64, 0x6f, 0x77, 0x6e, 0x6c,
+	0x6f, 0x61, 0x64, 0x30, 0x01, 0x42, 0x51, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
+	0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x6b, 0x72,
+	0x61, 0x74, 0x6f, 0x73, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d,
+	0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x69, 0x6e, 0x74, 0x65,
+	0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65,
+	0x63, 0x68, 0x6f, 0x3b, 0x65, 0x63, 0x68, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var file_stream_proto_goTypes = []interface{}{
+	(*emptypb.Empty)(nil),     // 0: google.protobuf.Empty
+	(*httpbody.HttpBody)(nil), // 1: google.api.HttpBody
+}
+var file_stream_proto_depIdxs = []int32{
+	0, // 0: echo.StreamService.Download:input_type -> google.protobuf.Empty
+	1, // 1: echo.StreamService.Download:output_type -> google.api.HttpBody
+	1, // [1:2] is the sub-list for method output_type
+	0, // [0:1] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_stream_proto_init() }
+func file_stream_proto_init() {
+	if File_stream_proto != nil {
+		return
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_stream_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   0,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_stream_proto_goTypes,
+		DependencyIndexes: file_stream_proto_depIdxs,
+	}.Build()
+	File_stream_proto = out.File
+	file_stream_proto_rawDesc = nil
+	file_stream_proto_goTypes = nil
+	file_stream_proto_depIdxs = nil
+}
diff --git a/internal/testproto/stream.proto b/internal/testproto/echo/stream.proto
similarity index 86%
rename from internal/testproto/stream.proto
rename to internal/testproto/echo/stream.proto
index f343c8f4..803d5474 100644
--- a/internal/testproto/stream.proto
+++ b/internal/testproto/echo/stream.proto
@@ -1,6 +1,8 @@
 syntax = "proto3";
-option go_package = "github.com/go-kratos/kratos/cmd/protoc-gen-go-http/internal/testproto;testproto";
-package testproto;
+
+package echo;
+
+option go_package = "github.com/go-kratos/kratos/cmd/protoc-gen-go-http/internal/testproto/echo;echo";
 
 import "google/api/annotations.proto";
 import "google/api/httpbody.proto";
diff --git a/internal/testproto/stream_grpc.pb.go b/internal/testproto/echo/stream_grpc.pb.go
similarity index 97%
rename from internal/testproto/stream_grpc.pb.go
rename to internal/testproto/echo/stream_grpc.pb.go
index 9dfe96f8..e178076b 100644
--- a/internal/testproto/stream_grpc.pb.go
+++ b/internal/testproto/echo/stream_grpc.pb.go
@@ -1,6 +1,6 @@
 // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 
-package testproto
+package echo
 
 import (
 	context "context"
@@ -32,7 +32,7 @@ func NewStreamServiceClient(cc grpc.ClientConnInterface) StreamServiceClient {
 }
 
 func (c *streamServiceClient) Download(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (StreamService_DownloadClient, error) {
-	stream, err := c.cc.NewStream(ctx, &StreamService_ServiceDesc.Streams[0], "/testproto.StreamService/Download", opts...)
+	stream, err := c.cc.NewStream(ctx, &StreamService_ServiceDesc.Streams[0], "/echo.StreamService/Download", opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -116,7 +116,7 @@ func (x *streamServiceDownloadServer) Send(m *httpbody.HttpBody) error {
 // It's only intended for direct use with grpc.RegisterService,
 // and not to be introspected or modified (even as a copy)
 var StreamService_ServiceDesc = grpc.ServiceDesc{
-	ServiceName: "testproto.StreamService",
+	ServiceName: "echo.StreamService",
 	HandlerType: (*StreamServiceServer)(nil),
 	Methods:     []grpc.MethodDesc{},
 	Streams: []grpc.StreamDesc{
diff --git a/internal/testproto/stream.pb.go b/internal/testproto/stream.pb.go
deleted file mode 100644
index d2fb0bbb..00000000
--- a/internal/testproto/stream.pb.go
+++ /dev/null
@@ -1,86 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// 	protoc-gen-go v1.26.0
-// 	protoc        v3.17.3
-// source: stream.proto
-
-package testproto
-
-import (
-	_ "google.golang.org/genproto/googleapis/api/annotations"
-	httpbody "google.golang.org/genproto/googleapis/api/httpbody"
-	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
-	emptypb "google.golang.org/protobuf/types/known/emptypb"
-	reflect "reflect"
-)
-
-const (
-	// Verify that this generated code is sufficiently up-to-date.
-	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
-	// Verify that runtime/protoimpl is sufficiently up-to-date.
-	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-var File_stream_proto protoreflect.FileDescriptor
-
-var file_stream_proto_rawDesc = []byte{
-	0x0a, 0x0c, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09,
-	0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
-	0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
-	0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
-	0x61, 0x70, 0x69, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x62, 0x6f, 0x64, 0x79, 0x2e, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32,
-	0x69, 0x0a, 0x0d, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
-	0x12, 0x58, 0x0a, 0x08, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x16, 0x2e, 0x67,
-	0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45,
-	0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70,
-	0x69, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93,
-	0x02, 0x16, 0x12, 0x14, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f,
-	0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x30, 0x01, 0x42, 0x51, 0x5a, 0x4f, 0x67, 0x69,
-	0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74,
-	0x6f, 0x73, 0x2f, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x70, 0x72,
-	0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x68, 0x74, 0x74, 0x70,
-	0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72,
-	0x6f, 0x74, 0x6f, 0x3b, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x33,
-}
-
-var file_stream_proto_goTypes = []interface{}{
-	(*emptypb.Empty)(nil),     // 0: google.protobuf.Empty
-	(*httpbody.HttpBody)(nil), // 1: google.api.HttpBody
-}
-var file_stream_proto_depIdxs = []int32{
-	0, // 0: testproto.StreamService.Download:input_type -> google.protobuf.Empty
-	1, // 1: testproto.StreamService.Download:output_type -> google.api.HttpBody
-	1, // [1:2] is the sub-list for method output_type
-	0, // [0:1] is the sub-list for method input_type
-	0, // [0:0] is the sub-list for extension type_name
-	0, // [0:0] is the sub-list for extension extendee
-	0, // [0:0] is the sub-list for field type_name
-}
-
-func init() { file_stream_proto_init() }
-func file_stream_proto_init() {
-	if File_stream_proto != nil {
-		return
-	}
-	type x struct{}
-	out := protoimpl.TypeBuilder{
-		File: protoimpl.DescBuilder{
-			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_stream_proto_rawDesc,
-			NumEnums:      0,
-			NumMessages:   0,
-			NumExtensions: 0,
-			NumServices:   1,
-		},
-		GoTypes:           file_stream_proto_goTypes,
-		DependencyIndexes: file_stream_proto_depIdxs,
-	}.Build()
-	File_stream_proto = out.File
-	file_stream_proto_rawDesc = nil
-	file_stream_proto_goTypes = nil
-	file_stream_proto_depIdxs = nil
-}
diff --git a/transport/http/binding/proto_test.go b/transport/http/binding/encode_test.go
similarity index 79%
rename from transport/http/binding/proto_test.go
rename to transport/http/binding/encode_test.go
index 49255174..bf2ee291 100644
--- a/transport/http/binding/proto_test.go
+++ b/transport/http/binding/encode_test.go
@@ -12,6 +12,12 @@ func TestProtoPath(t *testing.T) {
 		t.Fatalf("proto path not expected!actual: %s ", url)
 	}
 
+	url = EncodeURL("http://helloworld.Greeter/helloworld/{name}/sub/{sub.naming}", &HelloRequest{Name: "test", Sub: &Sub{Name: "5566!!!"}}, false)
+	fmt.Println(url)
+	if url != `http://helloworld.Greeter/helloworld/test/sub/5566!!!` {
+		t.Fatalf("proto path not expected!actual: %s ", url)
+	}
+
 	url = EncodeURL("http://helloworld.Greeter/helloworld/sub", &HelloRequest{Name: "test", Sub: &Sub{Name: "2233!!!"}}, false)
 	fmt.Println(url)
 	if url != `http://helloworld.Greeter/helloworld/sub` {
diff --git a/transport/http/binding/test.pb.go b/transport/http/binding/test.pb.go
index 99f924dd..b4bd2868 100644
--- a/transport/http/binding/test.pb.go
+++ b/transport/http/binding/test.pb.go
@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.26.0
-// 	protoc        v3.15.8
+// 	protoc-gen-go v1.27.1-devel
+// 	protoc        v3.17.2
 // source: test.proto
 
 package binding
@@ -81,7 +81,7 @@ type Sub struct {
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	Name string `protobuf:"bytes,1,opt,name=name,json=naming,proto3" json:"name,omitempty"`
 }
 
 func (x *Sub) Reset() {
@@ -131,12 +131,12 @@ var file_test_proto_rawDesc = []byte{
 	0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
 	0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x03, 0x73, 0x75, 0x62,
 	0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67,
-	0x2e, 0x53, 0x75, 0x62, 0x52, 0x03, 0x73, 0x75, 0x62, 0x22, 0x19, 0x0a, 0x03, 0x53, 0x75, 0x62,
-	0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
-	0x6e, 0x61, 0x6d, 0x65, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
-	0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x6b, 0x72, 0x61,
-	0x74, 0x6f, 0x73, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x62, 0x69,
-	0x6e, 0x64, 0x69, 0x6e, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x2e, 0x53, 0x75, 0x62, 0x52, 0x03, 0x73, 0x75, 0x62, 0x22, 0x1b, 0x0a, 0x03, 0x53, 0x75, 0x62,
+	0x12, 0x14, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
+	0x6e, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
+	0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x6b,
+	0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f,
+	0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
diff --git a/transport/http/binding/test.proto b/transport/http/binding/test.proto
index cf4b430d..a2d8b0d3 100644
--- a/transport/http/binding/test.proto
+++ b/transport/http/binding/test.proto
@@ -11,5 +11,5 @@ message HelloRequest {
 }
 
 message Sub{
-  string name = 1;
+  string name = 1 [json_name="naming"];
 }