Repository: go-kratos/kratos
Pull request #2397 (2022-09-22 06:05:13)

fix(metadata): sort services by lexicographical order on ListServices
It's out of order on the reply of ListServices, which is so complex for human reading.

![image](https://user-images.githubusercontent.com/3887050/191670162-64925425-ebb4-4de8-9519-4d4025ea20a6.png)


codecov-commenter: # [Codecov](https://codecov.io/gh/go-kratos/kratos/pull/2397?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos) Report
> Merging [#2397](https://codecov.io/gh/go-kratos/kratos/pull/2397?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos) (cc8a5f8) into [main](https://codecov.io/gh/go-kratos/kratos/commit/7866ff75fd6c1174f4a7b49ddf26a93fe38bef1a?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos) (7866ff7) will **not change** coverage.
> The diff coverage is `n/a`.

```diff
@@           Coverage Diff           @@
##             main    #2397   +/-   ##
=======================================
  Coverage   85.36%   85.36%           
=======================================
  Files          88       88           
  Lines        3764     3764           
=======================================
  Hits         3213     3213           
  Misses        384      384           
  Partials      167      167           
```



Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-kratos)

deagon: recheck

Patch:
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 552fef4a..d2a527c6 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -13,7 +13,7 @@ jobs:
   build:
     strategy:
       matrix:
-        go: [1.16, 1.17, 1.18]
+        go: [1.16, 1.17, 1.18, 1.19]
     name: build & test
     runs-on: ubuntu-latest
     services:
diff --git a/.golangci.yml b/.golangci.yml
index 441db5ee..06ee200c 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -31,6 +31,7 @@ linters:
     - varcheck
     - whitespace
     - wastedassign
+    - unconvert
 
   # don't enable:
   # - asciicheck
@@ -66,3 +67,5 @@ linters-settings:
   gocyclo:
     # recommend 10-20
     min-complexity: 50
+  goimports:
+    local-prefixes: github.com/go-kratos/kratos # Put imports beginning with prefix after 3rd-party packages
diff --git a/api/metadata/server.go b/api/metadata/server.go
index 96f0e1e6..b1c4c17b 100644
--- a/api/metadata/server.go
+++ b/api/metadata/server.go
@@ -7,17 +7,19 @@ import (
 	"errors"
 	"fmt"
 	"io"
+	"sort"
 	"sync"
 
-	"github.com/go-kratos/kratos/v2/log"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 	"google.golang.org/protobuf/proto"
 	"google.golang.org/protobuf/reflect/protodesc"
-	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	"google.golang.org/protobuf/reflect/protoreflect"
 	"google.golang.org/protobuf/reflect/protoregistry"
 	dpb "google.golang.org/protobuf/types/descriptorpb"
+
+	"github.com/go-kratos/kratos/v2/log"
 )
 
 // Server is api meta server
@@ -114,6 +116,8 @@ func (s *Server) ListServices(ctx context.Context, in *ListServicesRequest) (*Li
 			reply.Methods = append(reply.Methods, fmt.Sprintf("/%s/%s", name, method))
 		}
 	}
+	sort.Strings(reply.Services)
+	sort.Strings(reply.Methods)
 	return reply, nil
 }
 
diff --git a/cmd/kratos/internal/base/vcs_url.go b/cmd/kratos/internal/base/vcs_url.go
index ef76db30..6d3aef12 100644
--- a/cmd/kratos/internal/base/vcs_url.go
+++ b/cmd/kratos/internal/base/vcs_url.go
@@ -8,7 +8,7 @@ import (
 )
 
 var (
-	scpSyntaxRe = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`)
+	scpSyntaxRe = regexp.MustCompile(`^(\w+)@([\w.-]+):(.*)$`)
 	scheme      = []string{"git", "https", "http", "git+ssh", "ssh", "file", "ftp", "ftps"}
 )
 
diff --git a/cmd/kratos/internal/project/add.go b/cmd/kratos/internal/project/add.go
index f4c1b88c..9f30bfcb 100644
--- a/cmd/kratos/internal/project/add.go
+++ b/cmd/kratos/internal/project/add.go
@@ -8,6 +8,7 @@ import (
 
 	"github.com/AlecAivazis/survey/v2"
 	"github.com/fatih/color"
+
 	"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
 )
 
diff --git a/cmd/kratos/internal/project/project.go b/cmd/kratos/internal/project/project.go
index 8ea7f2a9..271ad373 100644
--- a/cmd/kratos/internal/project/project.go
+++ b/cmd/kratos/internal/project/project.go
@@ -9,8 +9,9 @@ import (
 	"time"
 
 	"github.com/AlecAivazis/survey/v2"
-	"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
 	"github.com/spf13/cobra"
+
+	"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
 )
 
 // CmdNew represents the new command.
diff --git a/cmd/kratos/version.go b/cmd/kratos/version.go
index 9d205cbc..a616f715 100644
--- a/cmd/kratos/version.go
+++ b/cmd/kratos/version.go
@@ -1,4 +1,4 @@
 package main
 
 // release is the current kratos tool version.
-const release = "v2.5.0"
+const release = "v2.5.1"
diff --git a/cmd/protoc-gen-go-errors/errors.go b/cmd/protoc-gen-go-errors/errors.go
index 6a097330..522c2968 100644
--- a/cmd/protoc-gen-go-errors/errors.go
+++ b/cmd/protoc-gen-go-errors/errors.go
@@ -8,9 +8,10 @@ import (
 	"golang.org/x/text/cases"
 	"golang.org/x/text/language"
 
-	"github.com/go-kratos/kratos/cmd/protoc-gen-go-errors/v2/errors"
 	"google.golang.org/protobuf/compiler/protogen"
 	"google.golang.org/protobuf/proto"
+
+	"github.com/go-kratos/kratos/cmd/protoc-gen-go-errors/v2/errors"
 )
 
 const (
diff --git a/cmd/protoc-gen-go-errors/version.go b/cmd/protoc-gen-go-errors/version.go
index 71fced3e..8061323f 100644
--- a/cmd/protoc-gen-go-errors/version.go
+++ b/cmd/protoc-gen-go-errors/version.go
@@ -1,4 +1,4 @@
 package main
 
 // release is the current protoc-gen-go-errors version.
-const release = "v2.5.0"
+const release = "v2.5.1"
diff --git a/cmd/protoc-gen-go-http/http.go b/cmd/protoc-gen-go-http/http.go
index d8827722..a9eff9a3 100644
--- a/cmd/protoc-gen-go-http/http.go
+++ b/cmd/protoc-gen-go-http/http.go
@@ -213,7 +213,7 @@ func buildPathVars(path string) (res map[string]*string) {
 	if strings.HasSuffix(path, "/") {
 		fmt.Fprintf(os.Stderr, "\u001B[31mWARN\u001B[m: Path %s should not end with \"/\" \n", path)
 	}
-	pattern := regexp.MustCompile(`(?i){([a-z\.0-9_\s]*)=?([^{}]*)}`)
+	pattern := regexp.MustCompile(`(?i){([a-z.0-9_\s]*)=?([^{}]*)}`)
 	matches := pattern.FindAllStringSubmatch(path, -1)
 	res = make(map[string]*string, len(matches))
 	for _, m := range matches {
diff --git a/cmd/protoc-gen-go-http/version.go b/cmd/protoc-gen-go-http/version.go
index 065e7dd5..25b73c2f 100644
--- a/cmd/protoc-gen-go-http/version.go
+++ b/cmd/protoc-gen-go-http/version.go
@@ -1,4 +1,4 @@
 package main
 
 // release is the current protoc-gen-go-http version.
-const release = "v2.5.0"
+const release = "v2.5.1"
diff --git a/config/file/watcher.go b/config/file/watcher.go
index 4c00b046..ea309fa8 100644
--- a/config/file/watcher.go
+++ b/config/file/watcher.go
@@ -6,6 +6,7 @@ import (
 	"path/filepath"
 
 	"github.com/fsnotify/fsnotify"
+
 	"github.com/go-kratos/kratos/v2/config"
 )
 
diff --git a/config/value.go b/config/value.go
index 46417e77..9f6234f5 100644
--- a/config/value.go
+++ b/config/value.go
@@ -144,10 +144,8 @@ func (v *atomicValue) String() (string, error) {
 		return fmt.Sprint(val), nil
 	case []byte:
 		return string(val), nil
-	default:
-		if s, ok := val.(fmt.Stringer); ok {
-			return s.String(), nil
-		}
+	case fmt.Stringer:
+		return val.String(), nil
 	}
 	return "", fmt.Errorf("type assert to %v failed", reflect.TypeOf(v.Load()))
 }
diff --git a/contrib/config/apollo/apollo.go b/contrib/config/apollo/apollo.go
index 5f868bab..259ed1a9 100644
--- a/contrib/config/apollo/apollo.go
+++ b/contrib/config/apollo/apollo.go
@@ -10,6 +10,7 @@ import (
 	"github.com/apolloconfig/agollo/v4/constant"
 	apolloConfig "github.com/apolloconfig/agollo/v4/env/config"
 	"github.com/apolloconfig/agollo/v4/extension"
+
 	"github.com/go-kratos/kratos/v2/encoding"
 )
 
diff --git a/contrib/config/consul/config.go b/contrib/config/consul/config.go
index f42611e0..0404801b 100644
--- a/contrib/config/consul/config.go
+++ b/contrib/config/consul/config.go
@@ -6,8 +6,9 @@ import (
 	"path/filepath"
 	"strings"
 
-	"github.com/go-kratos/kratos/v2/config"
 	"github.com/hashicorp/consul/api"
+
+	"github.com/go-kratos/kratos/v2/config"
 )
 
 // Option is etcd config option.
@@ -27,9 +28,9 @@ func WithContext(ctx context.Context) Option {
 
 // WithPath is config path
 func WithPath(p string) Option {
-	return Option(func(o *options) {
+	return func(o *options) {
 		o.path = p
-	})
+	}
 }
 
 type source struct {
diff --git a/contrib/config/consul/watcher.go b/contrib/config/consul/watcher.go
index baee9ef6..5c70d6f8 100644
--- a/contrib/config/consul/watcher.go
+++ b/contrib/config/consul/watcher.go
@@ -3,9 +3,10 @@ package consul
 import (
 	"context"
 
-	"github.com/go-kratos/kratos/v2/config"
 	"github.com/hashicorp/consul/api"
 	"github.com/hashicorp/consul/api/watch"
+
+	"github.com/go-kratos/kratos/v2/config"
 )
 
 type watcher struct {
diff --git a/contrib/config/etcd/README.md b/contrib/config/etcd/README.md
index d7668745..d69edd82 100644
--- a/contrib/config/etcd/README.md
+++ b/contrib/config/etcd/README.md
@@ -30,12 +30,16 @@ if err != nil {
 c := config.New(config.WithSource(source))
 defer c.Close()
 
+// load sources before get
+if err := c.Load(); err != nil {
+    log.Fatalln(err)
+}
+
 // acquire config value
 foo, err := c.Value("/app-config").String()
 if err != nil {
-    log.Println(err)
+    log.Fatalln(err)
 }
-println(foo)
 
+log.Println(foo)
 ```
-
diff --git a/contrib/config/etcd/config.go b/contrib/config/etcd/config.go
index 37059e10..76045a58 100644
--- a/contrib/config/etcd/config.go
+++ b/contrib/config/etcd/config.go
@@ -6,8 +6,9 @@ import (
 	"path/filepath"
 	"strings"
 
-	"github.com/go-kratos/kratos/v2/config"
 	clientv3 "go.etcd.io/etcd/client/v3"
+
+	"github.com/go-kratos/kratos/v2/config"
 )
 
 // Option is etcd config option.
diff --git a/contrib/config/etcd/watcher.go b/contrib/config/etcd/watcher.go
index 388c2dd8..dd2ea911 100644
--- a/contrib/config/etcd/watcher.go
+++ b/contrib/config/etcd/watcher.go
@@ -3,8 +3,9 @@ package etcd
 import (
 	"context"
 
-	"github.com/go-kratos/kratos/v2/config"
 	clientv3 "go.etcd.io/etcd/client/v3"
+
+	"github.com/go-kratos/kratos/v2/config"
 )
 
 type watcher struct {
diff --git a/contrib/config/kubernetes/config.go b/contrib/config/kubernetes/config.go
index c66b837f..12026fe8 100644
--- a/contrib/config/kubernetes/config.go
+++ b/contrib/config/kubernetes/config.go
@@ -7,12 +7,13 @@ import (
 	"path/filepath"
 	"strings"
 
-	"github.com/go-kratos/kratos/v2/config"
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/rest"
 	"k8s.io/client-go/tools/clientcmd"
+
+	"github.com/go-kratos/kratos/v2/config"
 )
 
 // Option is kubernetes option.
diff --git a/contrib/config/kubernetes/watcher.go b/contrib/config/kubernetes/watcher.go
index 87872b8d..c13a8a7e 100644
--- a/contrib/config/kubernetes/watcher.go
+++ b/contrib/config/kubernetes/watcher.go
@@ -4,10 +4,11 @@ import (
 	"context"
 	"fmt"
 
-	"github.com/go-kratos/kratos/v2/config"
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/watch"
+
+	"github.com/go-kratos/kratos/v2/config"
 )
 
 type watcher struct {
diff --git a/contrib/config/nacos/watcher.go b/contrib/config/nacos/watcher.go
index e190b688..fd528af7 100644
--- a/contrib/config/nacos/watcher.go
+++ b/contrib/config/nacos/watcher.go
@@ -5,8 +5,9 @@ import (
 	"path/filepath"
 	"strings"
 
-	"github.com/go-kratos/kratos/v2/config"
 	"github.com/nacos-group/nacos-sdk-go/vo"
+
+	"github.com/go-kratos/kratos/v2/config"
 )
 
 type Watcher struct {
diff --git a/contrib/encoding/msgpack/go.mod b/contrib/encoding/msgpack/go.mod
index 5d78c21b..5b6a1f7e 100644
--- a/contrib/encoding/msgpack/go.mod
+++ b/contrib/encoding/msgpack/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/encoding/msgpack/v2
 go 1.16
 
 require (
-	github.com/go-kratos/kratos/v2 v2.5.0
+	github.com/go-kratos/kratos/v2 v2.5.1
 	github.com/vmihailenco/msgpack/v5 v5.3.5
 )
 
diff --git a/contrib/log/aliyun/aliyun.go b/contrib/log/aliyun/aliyun.go
index 1be5f764..351de69d 100644
--- a/contrib/log/aliyun/aliyun.go
+++ b/contrib/log/aliyun/aliyun.go
@@ -2,13 +2,15 @@ package aliyun
 
 import (
 	"encoding/json"
+	"fmt"
 	"strconv"
 	"time"
 
 	sls "github.com/aliyun/aliyun-log-go-sdk"
 	"github.com/aliyun/aliyun-log-go-sdk/producer"
-	log "github.com/go-kratos/kratos/v2/log"
 	"google.golang.org/protobuf/proto"
+
+	"github.com/go-kratos/kratos/v2/log"
 )
 
 // Logger see more detail https://github.com/aliyun/aliyun-log-go-sdk
@@ -126,7 +128,7 @@ func NewAliyunLog(options ...Option) Logger {
 	}
 }
 
-// toString 任意类型转string
+// toString convert any type to string
 func toString(v interface{}) string {
 	var key string
 	if v == nil {
@@ -159,8 +161,12 @@ func toString(v interface{}) string {
 		key = strconv.FormatUint(v, 10)
 	case string:
 		key = v
+	case bool:
+		key = strconv.FormatBool(v)
 	case []byte:
 		key = string(v)
+	case fmt.Stringer:
+		key = v.String()
 	default:
 		newValue, _ := json.Marshal(v)
 		key = string(newValue)
diff --git a/contrib/log/aliyun/go.mod b/contrib/log/aliyun/go.mod
index efe1b827..73edfb73 100644
--- a/contrib/log/aliyun/go.mod
+++ b/contrib/log/aliyun/go.mod
@@ -4,7 +4,7 @@ go 1.16
 
 require (
 	github.com/aliyun/aliyun-log-go-sdk v0.1.37
-	github.com/go-kratos/kratos/v2 v2.5.0
+	github.com/go-kratos/kratos/v2 v2.5.1
 	google.golang.org/protobuf v1.28.1
 )
 
diff --git a/contrib/log/fluent/fluent.go b/contrib/log/fluent/fluent.go
index 07a15b86..86e86993 100644
--- a/contrib/log/fluent/fluent.go
+++ b/contrib/log/fluent/fluent.go
@@ -8,6 +8,7 @@ import (
 	"time"
 
 	"github.com/fluent/fluent-logger-golang/fluent"
+
 	"github.com/go-kratos/kratos/v2/log"
 )
 
diff --git a/contrib/log/fluent/go.mod b/contrib/log/fluent/go.mod
index b316425a..8b3a4efc 100644
--- a/contrib/log/fluent/go.mod
+++ b/contrib/log/fluent/go.mod
@@ -5,7 +5,7 @@ go 1.16
 require (
 	github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
 	github.com/fluent/fluent-logger-golang v1.9.0
-	github.com/go-kratos/kratos/v2 v2.5.0
+	github.com/go-kratos/kratos/v2 v2.5.1
 	github.com/kr/pretty v0.3.0 // indirect
 	github.com/tinylib/msgp v1.1.6 // indirect
 )
diff --git a/contrib/log/logrus/go.mod b/contrib/log/logrus/go.mod
index c41e4ecc..5d923e1c 100644
--- a/contrib/log/logrus/go.mod
+++ b/contrib/log/logrus/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/log/logrus/v2
 go 1.16
 
 require (
-	github.com/go-kratos/kratos/v2 v2.5.0
+	github.com/go-kratos/kratos/v2 v2.5.1
 	github.com/sirupsen/logrus v1.8.1
 )
 
diff --git a/contrib/log/logrus/logrus.go b/contrib/log/logrus/logrus.go
index b08ba6e1..6fda38c5 100644
--- a/contrib/log/logrus/logrus.go
+++ b/contrib/log/logrus/logrus.go
@@ -1,8 +1,9 @@
 package logrus
 
 import (
-	"github.com/go-kratos/kratos/v2/log"
 	"github.com/sirupsen/logrus"
+
+	"github.com/go-kratos/kratos/v2/log"
 )
 
 var _ log.Logger = (*Logger)(nil)
diff --git a/contrib/log/tencent/go.mod b/contrib/log/tencent/go.mod
index 2d3fa7dc..d5a758f0 100644
--- a/contrib/log/tencent/go.mod
+++ b/contrib/log/tencent/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/log/tencent/v2
 go 1.16
 
 require (
-	github.com/go-kratos/kratos/v2 v2.5.0
+	github.com/go-kratos/kratos/v2 v2.5.1
 	github.com/tencentcloud/tencentcloud-cls-sdk-go v1.0.2
 	google.golang.org/protobuf v1.28.0
 )
diff --git a/contrib/log/tencent/tencent.go b/contrib/log/tencent/tencent.go
index 5d7267f2..8becf788 100644
--- a/contrib/log/tencent/tencent.go
+++ b/contrib/log/tencent/tencent.go
@@ -6,9 +6,10 @@ import (
 	"strconv"
 	"time"
 
-	log "github.com/go-kratos/kratos/v2/log"
 	cls "github.com/tencentcloud/tencentcloud-cls-sdk-go"
 	"google.golang.org/protobuf/proto"
+
+	"github.com/go-kratos/kratos/v2/log"
 )
 
 type Logger interface {
@@ -114,7 +115,7 @@ func NewLogger(options ...Option) (Logger, error) {
 	}, nil
 }
 
-// toString any type to string
+// toString convert any type to string
 func toString(v interface{}) string {
 	var key string
 	if v == nil {
@@ -145,6 +146,12 @@ func toString(v interface{}) string {
 		key = strconv.FormatInt(v, 10)
 	case uint64:
 		key = strconv.FormatUint(v, 10)
+	case string:
+		key = v
+	case bool:
+		key = strconv.FormatBool(v)
+	case []byte:
+		key = string(v)
 	case fmt.Stringer:
 		key = v.String()
 	default:
diff --git a/contrib/log/zap/go.mod b/contrib/log/zap/go.mod
index 0a8e74f6..8f8d5a9a 100644
--- a/contrib/log/zap/go.mod
+++ b/contrib/log/zap/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/log/zap/v2
 go 1.16
 
 require (
-	github.com/go-kratos/kratos/v2 v2.5.0
+	github.com/go-kratos/kratos/v2 v2.5.1
 	go.uber.org/zap v1.23.0
 )
 
diff --git a/contrib/log/zap/zap.go b/contrib/log/zap/zap.go
index 5929c486..511381f9 100644
--- a/contrib/log/zap/zap.go
+++ b/contrib/log/zap/zap.go
@@ -3,8 +3,9 @@ package zap
 import (
 	"fmt"
 
-	"github.com/go-kratos/kratos/v2/log"
 	"go.uber.org/zap"
+
+	"github.com/go-kratos/kratos/v2/log"
 )
 
 var _ log.Logger = (*Logger)(nil)
diff --git a/contrib/metrics/datadog/go.mod b/contrib/metrics/datadog/go.mod
index 206ccf4e..78f50039 100644
--- a/contrib/metrics/datadog/go.mod
+++ b/contrib/metrics/datadog/go.mod
@@ -5,7 +5,7 @@ go 1.16
 require (
 	github.com/DataDog/datadog-go v4.8.3+incompatible
 	github.com/Microsoft/go-winio v0.5.2 // indirect
-	github.com/go-kratos/kratos/v2 v2.5.0
+	github.com/go-kratos/kratos/v2 v2.5.1
 )
 
 replace github.com/go-kratos/kratos/v2 => ../../../
diff --git a/contrib/metrics/prometheus/counter.go b/contrib/metrics/prometheus/counter.go
index 8b90beab..5873c017 100644
--- a/contrib/metrics/prometheus/counter.go
+++ b/contrib/metrics/prometheus/counter.go
@@ -1,8 +1,9 @@
 package prometheus
 
 import (
-	"github.com/go-kratos/kratos/v2/metrics"
 	"github.com/prometheus/client_golang/prometheus"
+
+	"github.com/go-kratos/kratos/v2/metrics"
 )
 
 var _ metrics.Counter = (*counter)(nil)
diff --git a/contrib/metrics/prometheus/gauge.go b/contrib/metrics/prometheus/gauge.go
index 6df11d69..25750b6c 100644
--- a/contrib/metrics/prometheus/gauge.go
+++ b/contrib/metrics/prometheus/gauge.go
@@ -1,8 +1,9 @@
 package prometheus
 
 import (
-	"github.com/go-kratos/kratos/v2/metrics"
 	"github.com/prometheus/client_golang/prometheus"
+
+	"github.com/go-kratos/kratos/v2/metrics"
 )
 
 var _ metrics.Gauge = (*gauge)(nil)
diff --git a/contrib/metrics/prometheus/go.mod b/contrib/metrics/prometheus/go.mod
index c6a1b5df..462f13f1 100644
--- a/contrib/metrics/prometheus/go.mod
+++ b/contrib/metrics/prometheus/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/metrics/prometheus/v2
 go 1.16
 
 require (
-	github.com/go-kratos/kratos/v2 v2.5.0
+	github.com/go-kratos/kratos/v2 v2.5.1
 	github.com/prometheus/client_golang v1.12.2
 	github.com/prometheus/common v0.37.0
 )
diff --git a/contrib/metrics/prometheus/histogram.go b/contrib/metrics/prometheus/histogram.go
index 81b3b281..a0245d73 100644
--- a/contrib/metrics/prometheus/histogram.go
+++ b/contrib/metrics/prometheus/histogram.go
@@ -1,8 +1,9 @@
 package prometheus
 
 import (
-	"github.com/go-kratos/kratos/v2/metrics"
 	"github.com/prometheus/client_golang/prometheus"
+
+	"github.com/go-kratos/kratos/v2/metrics"
 )
 
 var _ metrics.Observer = (*histogram)(nil)
diff --git a/contrib/metrics/prometheus/summary.go b/contrib/metrics/prometheus/summary.go
index d8bcad91..25969edf 100644
--- a/contrib/metrics/prometheus/summary.go
+++ b/contrib/metrics/prometheus/summary.go
@@ -1,8 +1,9 @@
 package prometheus
 
 import (
-	"github.com/go-kratos/kratos/v2/metrics"
 	"github.com/prometheus/client_golang/prometheus"
+
+	"github.com/go-kratos/kratos/v2/metrics"
 )
 
 var _ metrics.Observer = (*summary)(nil)
diff --git a/contrib/opensergo/go.mod b/contrib/opensergo/go.mod
index 0b920de4..1c96a271 100644
--- a/contrib/opensergo/go.mod
+++ b/contrib/opensergo/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/opensergo/v2
 go 1.17
 
 require (
-	github.com/go-kratos/kratos/v2 v2.5.0
+	github.com/go-kratos/kratos/v2 v2.5.1
 	github.com/opensergo/opensergo-go v0.0.0-20220331070310-e5b01fee4d1c
 	golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2
 	google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd
diff --git a/contrib/registry/consul/go.mod b/contrib/registry/consul/go.mod
index 5a0965b4..e78723c7 100644
--- a/contrib/registry/consul/go.mod
+++ b/contrib/registry/consul/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/consul/v2
 go 1.16
 
 require (
-	github.com/go-kratos/kratos/v2 v2.5.0
+	github.com/go-kratos/kratos/v2 v2.5.1
 	github.com/hashicorp/consul/api v1.14.0
 )
 
diff --git a/contrib/registry/consul/registry.go b/contrib/registry/consul/registry.go
index d1c47d77..b2f2a3fe 100644
--- a/contrib/registry/consul/registry.go
+++ b/contrib/registry/consul/registry.go
@@ -7,14 +7,14 @@ import (
 	"sync/atomic"
 	"time"
 
-	"github.com/go-kratos/kratos/v2/registry"
-
 	"github.com/hashicorp/consul/api"
+
+	"github.com/go-kratos/kratos/v2/registry"
 )
 
 var (
-	_ registry.Registrar = &Registry{}
-	_ registry.Discovery = &Registry{}
+	_ registry.Registrar = (*Registry)(nil)
+	_ registry.Discovery = (*Registry)(nil)
 )
 
 // Option is consul registry option.
diff --git a/contrib/registry/discovery/discovery.go b/contrib/registry/discovery/discovery.go
index 32f3f67c..f439b0ca 100644
--- a/contrib/registry/discovery/discovery.go
+++ b/contrib/registry/discovery/discovery.go
@@ -10,9 +10,10 @@ import (
 	"sync/atomic"
 	"time"
 
-	"github.com/go-kratos/kratos/v2/log"
 	"github.com/go-resty/resty/v2"
 	"github.com/pkg/errors"
+
+	"github.com/go-kratos/kratos/v2/log"
 )
 
 type Discovery struct {
diff --git a/contrib/registry/discovery/go.mod b/contrib/registry/discovery/go.mod
index 407af47a..40b61cb0 100644
--- a/contrib/registry/discovery/go.mod
+++ b/contrib/registry/discovery/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/discovery/v2
 go 1.16
 
 require (
-	github.com/go-kratos/kratos/v2 v2.5.0
+	github.com/go-kratos/kratos/v2 v2.5.1
 	github.com/go-resty/resty/v2 v2.7.0
 	github.com/pkg/errors v0.9.1
 )
diff --git a/contrib/registry/etcd/go.mod b/contrib/registry/etcd/go.mod
index 952e8a55..1976385e 100644
--- a/contrib/registry/etcd/go.mod
+++ b/contrib/registry/etcd/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/etcd/v2
 go 1.16
 
 require (
-	github.com/go-kratos/kratos/v2 v2.5.0
+	github.com/go-kratos/kratos/v2 v2.5.1
 	go.etcd.io/etcd/client/v3 v3.5.4
 	google.golang.org/grpc v1.46.2
 )
diff --git a/contrib/registry/etcd/registry.go b/contrib/registry/etcd/registry.go
index 76c114a0..ca858c99 100644
--- a/contrib/registry/etcd/registry.go
+++ b/contrib/registry/etcd/registry.go
@@ -6,13 +6,14 @@ import (
 	"math/rand"
 	"time"
 
-	"github.com/go-kratos/kratos/v2/registry"
 	clientv3 "go.etcd.io/etcd/client/v3"
+
+	"github.com/go-kratos/kratos/v2/registry"
 )
 
 var (
-	_ registry.Registrar = &Registry{}
-	_ registry.Discovery = &Registry{}
+	_ registry.Registrar = (*Registry)(nil)
+	_ registry.Discovery = (*Registry)(nil)
 )
 
 // Option is etcd registry option.
diff --git a/contrib/registry/etcd/watcher.go b/contrib/registry/etcd/watcher.go
index a5bf63c4..0e531a99 100644
--- a/contrib/registry/etcd/watcher.go
+++ b/contrib/registry/etcd/watcher.go
@@ -3,8 +3,9 @@ package etcd
 import (
 	"context"
 
-	"github.com/go-kratos/kratos/v2/registry"
 	clientv3 "go.etcd.io/etcd/client/v3"
+
+	"github.com/go-kratos/kratos/v2/registry"
 )
 
 var _ registry.Watcher = (*watcher)(nil)
diff --git a/contrib/registry/eureka/client.go b/contrib/registry/eureka/client.go
index f2b4e96f..020a9a90 100644
--- a/contrib/registry/eureka/client.go
+++ b/contrib/registry/eureka/client.go
@@ -14,14 +14,14 @@ import (
 )
 
 const (
-	statusUp            = "UP"
-	statusDown          = "DOWN"
-	statusOutOfServeice = "OUT_OF_SERVICE"
-	heartbeatRetry      = 3
-	maxIdleConns        = 100
-	heartbeatTime       = 10
-	httpTimeout         = 3
-	refreshTime         = 30
+	statusUp           = "UP"
+	statusDown         = "DOWN"
+	statusOutOfService = "OUT_OF_SERVICE"
+	heartbeatRetry     = 3
+	maxIdleConns       = 100
+	heartbeatTime      = 10
+	httpTimeout        = 3
+	refreshTime        = 30
 )
 
 type Endpoint struct {
@@ -184,7 +184,7 @@ func (e *Client) FetchInstance(ctx context.Context, instanceID string) (m Instan
 }
 
 func (e *Client) Out(ctx context.Context, appID, instanceID string) error {
-	return e.do(ctx, "PUT", []string{"apps", appID, instanceID, fmt.Sprintf("status?value=%s", statusOutOfServeice)}, nil, nil)
+	return e.do(ctx, "PUT", []string{"apps", appID, instanceID, fmt.Sprintf("status?value=%s", statusOutOfService)}, nil, nil)
 }
 
 func (e *Client) Down(ctx context.Context, appID, instanceID string) error {
@@ -268,8 +268,8 @@ func (e *Client) Heartbeat(ep Endpoint) {
 }
 
 func (e *Client) cancelHeartbeat(appID string) {
-	defer e.lock.Unlock()
 	e.lock.Lock()
+	defer e.lock.Unlock()
 	if ch, ok := e.keepalive[appID]; ok {
 		ch <- struct{}{}
 	}
@@ -307,39 +307,50 @@ func (e *Client) buildAPI(currentTimes int, params ...string) string {
 	return strings.Join(params, "/")
 }
 
-func (e *Client) do(ctx context.Context, method string, params []string, input io.Reader, output interface{}) error {
-	for i := 0; i < e.maxRetry; i++ {
-		request, err := http.NewRequest(method, e.buildAPI(i, params...), input)
+func (e *Client) request(ctx context.Context, method string, params []string, input io.Reader, output interface{}, i int) (bool, error) {
+	request, err := http.NewRequestWithContext(ctx, method, e.buildAPI(i, params...), input)
+	if err != nil {
+		return false, err
+	}
+	request.Header.Add("User-Agent", "go-eureka-client")
+	request.Header.Add("Accept", "application/json;charset=UTF-8")
+	request.Header.Add("Content-Type", "application/json;charset=UTF-8")
+	resp, err := e.client.Do(request)
+	if err != nil {
+		return true, err
+	}
+	defer func() {
+		_, _ = io.Copy(io.Discard, resp.Body)
+		_ = resp.Body.Close()
+	}()
+
+	if output != nil && resp.StatusCode/100 == 2 {
+		data, err := io.ReadAll(resp.Body)
 		if err != nil {
-			return err
+			return false, err
 		}
-		request = request.WithContext(ctx)
-		request.Header.Add("User-Agent", "go-eureka-client")
-		request.Header.Add("Accept", "application/json;charset=UTF-8")
-		request.Header.Add("Content-Type", "application/json;charset=UTF-8")
-		resp, err := e.client.Do(request)
+		err = json.Unmarshal(data, output)
 		if err != nil {
-			continue
-		}
-		defer func() {
-			_, _ = io.Copy(io.Discard, resp.Body)
-			resp.Body.Close()
-		}()
-
-		if output != nil && resp.StatusCode/100 == 2 {
-			data, err := io.ReadAll(resp.Body)
-			if err != nil {
-				return err
-			}
-			if err = json.Unmarshal(data, output); err != nil {
-				return err
-			}
+			return false, err
 		}
+	}
 
-		if resp.StatusCode >= http.StatusBadRequest {
-			return fmt.Errorf("response Error %d", resp.StatusCode)
-		}
+	if resp.StatusCode >= http.StatusBadRequest {
+		return false, fmt.Errorf("response Error %d", resp.StatusCode)
+	}
 
+	return false, nil
+}
+
+func (e *Client) do(ctx context.Context, method string, params []string, input io.Reader, output interface{}) error {
+	for i := 0; i < e.maxRetry; i++ {
+		retry, err := e.request(ctx, method, params, input, output, i)
+		if retry {
+			continue
+		}
+		if err != nil {
+			return err
+		}
 		return nil
 	}
 	return fmt.Errorf("retry after %d times", e.maxRetry)
diff --git a/contrib/registry/eureka/register.go b/contrib/registry/eureka/register.go
index 62ee81cf..242ec910 100644
--- a/contrib/registry/eureka/register.go
+++ b/contrib/registry/eureka/register.go
@@ -11,8 +11,8 @@ import (
 )
 
 var (
-	_ registry.Registrar = &Registry{}
-	_ registry.Discovery = &Registry{}
+	_ registry.Registrar = (*Registry)(nil)
+	_ registry.Discovery = (*Registry)(nil)
 )
 
 type Option func(o *Registry)
@@ -92,12 +92,9 @@ func (r *Registry) Watch(ctx context.Context, serviceName string) (registry.Watc
 }
 
 func (r *Registry) Endpoints(service *registry.ServiceInstance) []Endpoint {
-	var (
-		res   = []Endpoint{}
-		start int
-	)
+	res := make([]Endpoint, 0, len(service.Endpoints))
 	for _, ep := range service.Endpoints {
-		start = strings.Index(ep, "//")
+		start := strings.Index(ep, "//")
 		end := strings.LastIndex(ep, ":")
 		appID := strings.ToUpper(service.Name)
 		ip := ep[start+2 : end]
diff --git a/contrib/registry/kubernetes/go.mod b/contrib/registry/kubernetes/go.mod
index cad07df0..3f20affb 100644
--- a/contrib/registry/kubernetes/go.mod
+++ b/contrib/registry/kubernetes/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/kubernetes/v2
 go 1.16
 
 require (
-	github.com/go-kratos/kratos/v2 v2.5.0
+	github.com/go-kratos/kratos/v2 v2.5.1
 	github.com/json-iterator/go v1.1.12
 	k8s.io/api v0.24.3
 	k8s.io/apimachinery v0.24.3
diff --git a/contrib/registry/kubernetes/registry.go b/contrib/registry/kubernetes/registry.go
index 25390362..987ef1e1 100644
--- a/contrib/registry/kubernetes/registry.go
+++ b/contrib/registry/kubernetes/registry.go
@@ -11,7 +11,6 @@ import (
 	"strings"
 	"time"
 
-	"github.com/go-kratos/kratos/v2/registry"
 	jsoniter "github.com/json-iterator/go"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -21,6 +20,8 @@ import (
 	"k8s.io/client-go/kubernetes"
 	listerv1 "k8s.io/client-go/listers/core/v1"
 	"k8s.io/client-go/tools/cache"
+
+	"github.com/go-kratos/kratos/v2/registry"
 )
 
 // Defines the key name of specific fields
diff --git a/contrib/registry/nacos/go.mod b/contrib/registry/nacos/go.mod
index bdfd037e..d6048dfc 100644
--- a/contrib/registry/nacos/go.mod
+++ b/contrib/registry/nacos/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/nacos/v2
 go 1.16
 
 require (
-	github.com/go-kratos/kratos/v2 v2.5.0
+	github.com/go-kratos/kratos/v2 v2.5.1
 	github.com/nacos-group/nacos-sdk-go v1.0.9
 )
 
diff --git a/contrib/registry/nacos/registry.go b/contrib/registry/nacos/registry.go
index 088cb8c2..1a3722b8 100644
--- a/contrib/registry/nacos/registry.go
+++ b/contrib/registry/nacos/registry.go
@@ -2,6 +2,7 @@ package nacos
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"net"
 	"net/url"
@@ -14,6 +15,8 @@ import (
 	"github.com/go-kratos/kratos/v2/registry"
 )
 
+var ErrServiceInstanceNameEmpty = errors.New("kratos/nacos: ServiceInstance.Name can not be empty")
+
 var (
 	_ registry.Registrar = (*Registry)(nil)
 	_ registry.Discovery = (*Registry)(nil)
@@ -82,7 +85,7 @@ func New(cli naming_client.INamingClient, opts ...Option) (r *Registry) {
 // Register the registration.
 func (r *Registry) Register(_ context.Context, si *registry.ServiceInstance) error {
 	if si.Name == "" {
-		return fmt.Errorf("kratos/nacos: serviceInstance.name can not be empty")
+		return ErrServiceInstanceNameEmpty
 	}
 	for _, endpoint := range si.Endpoints {
 		u, err := url.Parse(endpoint)
diff --git a/contrib/registry/nacos/watcher.go b/contrib/registry/nacos/watcher.go
index c5d652fc..78b4fc21 100644
--- a/contrib/registry/nacos/watcher.go
+++ b/contrib/registry/nacos/watcher.go
@@ -4,10 +4,11 @@ import (
 	"context"
 	"fmt"
 
-	"github.com/go-kratos/kratos/v2/registry"
 	"github.com/nacos-group/nacos-sdk-go/clients/naming_client"
 	"github.com/nacos-group/nacos-sdk-go/model"
 	"github.com/nacos-group/nacos-sdk-go/vo"
+
+	"github.com/go-kratos/kratos/v2/registry"
 )
 
 var _ registry.Watcher = (*watcher)(nil)
diff --git a/contrib/registry/polaris/go.mod b/contrib/registry/polaris/go.mod
index 2789a991..306fe927 100644
--- a/contrib/registry/polaris/go.mod
+++ b/contrib/registry/polaris/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/polaris/v2
 go 1.16
 
 require (
-	github.com/go-kratos/kratos/v2 v2.5.0
+	github.com/go-kratos/kratos/v2 v2.5.1
 	github.com/polarismesh/polaris-go v1.1.0
 )
 
diff --git a/contrib/registry/servicecomb/registry.go b/contrib/registry/servicecomb/registry.go
index 7dd388c9..894cf343 100644
--- a/contrib/registry/servicecomb/registry.go
+++ b/contrib/registry/servicecomb/registry.go
@@ -7,13 +7,12 @@ import (
 	"time"
 
 	"github.com/go-chassis/cari/discovery"
-	pb "github.com/go-chassis/cari/discovery"
 	"github.com/go-chassis/cari/pkg/errsvc"
 	"github.com/go-chassis/sc-client"
+	"github.com/gofrs/uuid"
 
 	"github.com/go-kratos/kratos/v2/log"
 	"github.com/go-kratos/kratos/v2/registry"
-	"github.com/gofrs/uuid"
 )
 
 func init() {
@@ -114,7 +113,7 @@ func (r *Registry) Register(_ context.Context, svcIns *registry.ServiceInstance)
 			return parseErr
 		}
 		// 若错误码显示服务未注册，直接返回
-		if svcErr.Code != pb.ErrServiceAlreadyExists {
+		if svcErr.Code != discovery.ErrServiceAlreadyExists {
 			return err
 		}
 		sid, err = r.cli.GetMicroServiceID(appID, ms.ServiceName, ms.Version, ms.Environment)
diff --git a/contrib/registry/servicecomb/watcher.go b/contrib/registry/servicecomb/watcher.go
index 2b2117e8..b1f4fccf 100644
--- a/contrib/registry/servicecomb/watcher.go
+++ b/contrib/registry/servicecomb/watcher.go
@@ -2,9 +2,9 @@ package servicecomb
 
 import (
 	"github.com/go-chassis/sc-client"
+	"golang.org/x/net/context"
 
 	"github.com/go-kratos/kratos/v2/registry"
-	"golang.org/x/net/context"
 )
 
 var _ registry.Watcher = (*Watcher)(nil)
diff --git a/contrib/registry/zookeeper/go.mod b/contrib/registry/zookeeper/go.mod
index a149d20a..09c35a1b 100644
--- a/contrib/registry/zookeeper/go.mod
+++ b/contrib/registry/zookeeper/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/zookeeper/v2
 go 1.16
 
 require (
-	github.com/go-kratos/kratos/v2 v2.5.0
+	github.com/go-kratos/kratos/v2 v2.5.1
 	github.com/go-zookeeper/zk v1.0.3
 	golang.org/x/sync v0.0.0-20220513210516-0976fa681c29
 )
diff --git a/contrib/registry/zookeeper/register.go b/contrib/registry/zookeeper/register.go
index 771a5bbc..8f21745d 100644
--- a/contrib/registry/zookeeper/register.go
+++ b/contrib/registry/zookeeper/register.go
@@ -12,8 +12,8 @@ import (
 )
 
 var (
-	_ registry.Registrar = &Registry{}
-	_ registry.Discovery = &Registry{}
+	_ registry.Registrar = (*Registry)(nil)
+	_ registry.Discovery = (*Registry)(nil)
 )
 
 // Option is etcd registry option.
diff --git a/contrib/registry/zookeeper/watcher.go b/contrib/registry/zookeeper/watcher.go
index f2009675..ddb98a84 100644
--- a/contrib/registry/zookeeper/watcher.go
+++ b/contrib/registry/zookeeper/watcher.go
@@ -6,8 +6,9 @@ import (
 	"path"
 	"sync/atomic"
 
-	"github.com/go-kratos/kratos/v2/registry"
 	"github.com/go-zookeeper/zk"
+
+	"github.com/go-kratos/kratos/v2/registry"
 )
 
 var _ registry.Watcher = (*watcher)(nil)
diff --git a/encoding/form/proto_decode.go b/encoding/form/proto_decode.go
index 47affee1..fcf46d46 100644
--- a/encoding/form/proto_decode.go
+++ b/encoding/form/proto_decode.go
@@ -99,6 +99,9 @@ func getDescriptorByFieldAndName(fields protoreflect.FieldDescriptors, fieldName
 }
 
 func populateField(fd protoreflect.FieldDescriptor, v protoreflect.Message, value string) error {
+	if value == "" {
+		return nil
+	}
 	val, err := parseField(fd, value)
 	if err != nil {
 		return fmt.Errorf("parsing field %q: %w", fd.FullName().Name(), err)
diff --git a/encoding/form/proto_encode.go b/encoding/form/proto_encode.go
index 28ebb0bc..94eac6ab 100644
--- a/encoding/form/proto_encode.go
+++ b/encoding/form/proto_encode.go
@@ -162,7 +162,7 @@ func encodeMessage(msgDescriptor protoreflect.MessageDescriptor, value protorefl
 	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")))
+		v := value.Message().Get(fd.ByName("value"))
 		return fmt.Sprint(v.Interface()), nil
 	case fieldMaskFullName:
 		m, ok := value.Message().Interface().(*fieldmaskpb.FieldMask)
diff --git a/encoding/json/json.go b/encoding/json/json.go
index d5e020b7..c1982190 100644
--- a/encoding/json/json.go
+++ b/encoding/json/json.go
@@ -4,9 +4,10 @@ import (
 	"encoding/json"
 	"reflect"
 
-	"github.com/go-kratos/kratos/v2/encoding"
 	"google.golang.org/protobuf/encoding/protojson"
 	"google.golang.org/protobuf/proto"
+
+	"github.com/go-kratos/kratos/v2/encoding"
 )
 
 // Name is the name registered for the json codec.
diff --git a/encoding/yaml/yaml.go b/encoding/yaml/yaml.go
index b2f885f0..1364b24c 100644
--- a/encoding/yaml/yaml.go
+++ b/encoding/yaml/yaml.go
@@ -1,8 +1,9 @@
 package yaml
 
 import (
-	"github.com/go-kratos/kratos/v2/encoding"
 	"gopkg.in/yaml.v3"
+
+	"github.com/go-kratos/kratos/v2/encoding"
 )
 
 // Name is the name registered for the yaml codec.
diff --git a/errors/errors.go b/errors/errors.go
index fd95ff3b..caf31cd3 100644
--- a/errors/errors.go
+++ b/errors/errors.go
@@ -4,9 +4,10 @@ import (
 	"errors"
 	"fmt"
 
-	httpstatus "github.com/go-kratos/kratos/v2/transport/http/status"
 	"google.golang.org/genproto/googleapis/rpc/errdetails"
 	"google.golang.org/grpc/status"
+
+	httpstatus "github.com/go-kratos/kratos/v2/transport/http/status"
 )
 
 const (
diff --git a/middleware/circuitbreaker/circuitbreaker.go b/middleware/circuitbreaker/circuitbreaker.go
index c7ab178e..31433ee7 100644
--- a/middleware/circuitbreaker/circuitbreaker.go
+++ b/middleware/circuitbreaker/circuitbreaker.go
@@ -5,6 +5,7 @@ import (
 
 	"github.com/go-kratos/aegis/circuitbreaker"
 	"github.com/go-kratos/aegis/circuitbreaker/sre"
+
 	"github.com/go-kratos/kratos/v2/errors"
 	"github.com/go-kratos/kratos/v2/internal/group"
 	"github.com/go-kratos/kratos/v2/middleware"
diff --git a/middleware/metadata/metadata.go b/middleware/metadata/metadata.go
index 5c29189f..da9e43a9 100644
--- a/middleware/metadata/metadata.go
+++ b/middleware/metadata/metadata.go
@@ -51,16 +51,19 @@ func Server(opts ...Option) middleware.Middleware {
 	}
 	return func(handler middleware.Handler) middleware.Handler {
 		return func(ctx context.Context, req interface{}) (reply interface{}, err error) {
-			if tr, ok := transport.FromServerContext(ctx); ok {
-				md := options.md.Clone()
-				header := tr.RequestHeader()
-				for _, k := range header.Keys() {
-					if options.hasPrefix(k) {
-						md.Set(k, header.Get(k))
-					}
+			tr, ok := transport.FromServerContext(ctx)
+			if !ok {
+				return handler(ctx, req)
+			}
+
+			md := options.md.Clone()
+			header := tr.RequestHeader()
+			for _, k := range header.Keys() {
+				if options.hasPrefix(k) {
+					md.Set(k, header.Get(k))
 				}
-				ctx = metadata.NewServerContext(ctx, md)
 			}
+			ctx = metadata.NewServerContext(ctx, md)
 			return handler(ctx, req)
 		}
 	}
@@ -76,25 +79,28 @@ func Client(opts ...Option) middleware.Middleware {
 	}
 	return func(handler middleware.Handler) middleware.Handler {
 		return func(ctx context.Context, req interface{}) (reply interface{}, err error) {
-			if tr, ok := transport.FromClientContext(ctx); ok {
-				header := tr.RequestHeader()
-				// x-md-local-
-				for k, v := range options.md {
+			tr, ok := transport.FromClientContext(ctx)
+			if !ok {
+				return handler(ctx, req)
+			}
+
+			header := tr.RequestHeader()
+			// x-md-local-
+			for k, v := range options.md {
+				header.Set(k, v)
+			}
+			if md, ok := metadata.FromClientContext(ctx); ok {
+				for k, v := range md {
 					header.Set(k, v)
 				}
-				if md, ok := metadata.FromClientContext(ctx); ok {
-					for k, v := range md {
+			}
+			// x-md-global-
+			if md, ok := metadata.FromServerContext(ctx); ok {
+				for k, v := range md {
+					if options.hasPrefix(k) {
 						header.Set(k, v)
 					}
 				}
-				// x-md-global-
-				if md, ok := metadata.FromServerContext(ctx); ok {
-					for k, v := range md {
-						if options.hasPrefix(k) {
-							header.Set(k, v)
-						}
-					}
-				}
 			}
 			return handler(ctx, req)
 		}
diff --git a/middleware/ratelimit/ratelimit.go b/middleware/ratelimit/ratelimit.go
index 5bfae27b..23f21753 100644
--- a/middleware/ratelimit/ratelimit.go
+++ b/middleware/ratelimit/ratelimit.go
@@ -5,6 +5,7 @@ import (
 
 	"github.com/go-kratos/aegis/ratelimit"
 	"github.com/go-kratos/aegis/ratelimit/bbr"
+
 	"github.com/go-kratos/kratos/v2/errors"
 	"github.com/go-kratos/kratos/v2/middleware"
 )
diff --git a/middleware/tracing/metadata.go b/middleware/tracing/metadata.go
index 01e51132..7ad82806 100644
--- a/middleware/tracing/metadata.go
+++ b/middleware/tracing/metadata.go
@@ -3,9 +3,10 @@ package tracing
 import (
 	"context"
 
+	"go.opentelemetry.io/otel/propagation"
+
 	"github.com/go-kratos/kratos/v2"
 	"github.com/go-kratos/kratos/v2/metadata"
-	"go.opentelemetry.io/otel/propagation"
 )
 
 const serviceHeader = "x-md-service-name"
diff --git a/middleware/tracing/span.go b/middleware/tracing/span.go
index 7edb914e..a0a9d462 100644
--- a/middleware/tracing/span.go
+++ b/middleware/tracing/span.go
@@ -57,10 +57,12 @@ func setClientSpan(ctx context.Context, span trace.Span, m interface{}) {
 }
 
 func setServerSpan(ctx context.Context, span trace.Span, m interface{}) {
-	attrs := []attribute.KeyValue{}
-	var remote string
-	var operation string
-	var rpcKind string
+	var (
+		attrs     []attribute.KeyValue
+		remote    string
+		operation string
+		rpcKind   string
+	)
 	tr, ok := transport.FromServerContext(ctx)
 	if ok {
 		operation = tr.Operation()
diff --git a/middleware/tracing/tracer.go b/middleware/tracing/tracer.go
index cf9115bb..798994f8 100644
--- a/middleware/tracing/tracer.go
+++ b/middleware/tracing/tracer.go
@@ -4,13 +4,14 @@ import (
 	"context"
 	"fmt"
 
-	"github.com/go-kratos/kratos/v2/errors"
 	"go.opentelemetry.io/otel"
 	"go.opentelemetry.io/otel/attribute"
 	"go.opentelemetry.io/otel/codes"
 	"go.opentelemetry.io/otel/propagation"
 	"go.opentelemetry.io/otel/trace"
 	"google.golang.org/protobuf/proto"
+
+	"github.com/go-kratos/kratos/v2/errors"
 )
 
 // Tracer is otel span tracer
diff --git a/middleware/tracing/tracing.go b/middleware/tracing/tracing.go
index 167725f4..b89ce0a2 100644
--- a/middleware/tracing/tracing.go
+++ b/middleware/tracing/tracing.go
@@ -5,10 +5,11 @@ import (
 
 	"github.com/go-kratos/kratos/v2/log"
 
-	"github.com/go-kratos/kratos/v2/middleware"
-	"github.com/go-kratos/kratos/v2/transport"
 	"go.opentelemetry.io/otel/propagation"
 	"go.opentelemetry.io/otel/trace"
+
+	"github.com/go-kratos/kratos/v2/middleware"
+	"github.com/go-kratos/kratos/v2/transport"
 )
 
 // Option is tracing option.
diff --git a/selector/default_node.go b/selector/default_node.go
index 186629e7..3554a3a1 100644
--- a/selector/default_node.go
+++ b/selector/default_node.go
@@ -6,6 +6,8 @@ import (
 	"github.com/go-kratos/kratos/v2/registry"
 )
 
+var _ Node = (*DefaultNode)(nil)
+
 // DefaultNode is selector node
 type DefaultNode struct {
 	scheme   string
diff --git a/selector/default_selector.go b/selector/default_selector.go
index 247af2e9..83b1ce9e 100644
--- a/selector/default_selector.go
+++ b/selector/default_selector.go
@@ -5,6 +5,11 @@ import (
 	"sync/atomic"
 )
 
+var (
+	_ Rebalancer = (*Default)(nil)
+	_ Builder    = (*DefaultBuilder)(nil)
+)
+
 // Default is composite selector.
 type Default struct {
 	NodeBuilder WeightedNodeBuilder
diff --git a/selector/node/direct/direct.go b/selector/node/direct/direct.go
index 62b30ed7..d32fc314 100644
--- a/selector/node/direct/direct.go
+++ b/selector/node/direct/direct.go
@@ -13,8 +13,8 @@ const (
 )
 
 var (
-	_ selector.WeightedNode        = &Node{}
-	_ selector.WeightedNodeBuilder = &Builder{}
+	_ selector.WeightedNode        = (*Node)(nil)
+	_ selector.WeightedNodeBuilder = (*Builder)(nil)
 )
 
 // Node is endpoint instance
diff --git a/selector/node/ewma/node.go b/selector/node/ewma/node.go
index 1707f108..4fed4aaa 100644
--- a/selector/node/ewma/node.go
+++ b/selector/node/ewma/node.go
@@ -21,8 +21,8 @@ const (
 )
 
 var (
-	_ selector.WeightedNode        = &Node{}
-	_ selector.WeightedNodeBuilder = &Builder{}
+	_ selector.WeightedNode        = (*Node)(nil)
+	_ selector.WeightedNodeBuilder = (*Builder)(nil)
 )
 
 // Node is endpoint instance
diff --git a/transport/grpc/balancer.go b/transport/grpc/balancer.go
index 948b736b..f42dc23b 100644
--- a/transport/grpc/balancer.go
+++ b/transport/grpc/balancer.go
@@ -1,13 +1,13 @@
 package grpc
 
 import (
-	"github.com/go-kratos/kratos/v2/registry"
-	"github.com/go-kratos/kratos/v2/selector"
-	"github.com/go-kratos/kratos/v2/transport"
-
 	"google.golang.org/grpc/balancer"
 	"google.golang.org/grpc/balancer/base"
 	"google.golang.org/grpc/metadata"
+
+	"github.com/go-kratos/kratos/v2/registry"
+	"github.com/go-kratos/kratos/v2/selector"
+	"github.com/go-kratos/kratos/v2/transport"
 )
 
 const (
@@ -15,8 +15,8 @@ const (
 )
 
 var (
-	_ base.PickerBuilder = &balancerBuilder{}
-	_ balancer.Picker    = &balancerPicker{}
+	_ base.PickerBuilder = (*balancerBuilder)(nil)
+	_ balancer.Picker    = (*balancerPicker)(nil)
 )
 
 func init() {
diff --git a/transport/grpc/codec.go b/transport/grpc/codec.go
index 19670bba..231f114f 100644
--- a/transport/grpc/codec.go
+++ b/transport/grpc/codec.go
@@ -3,10 +3,11 @@ package grpc
 import (
 	"fmt"
 
-	enc "github.com/go-kratos/kratos/v2/encoding"
-	"github.com/go-kratos/kratos/v2/encoding/json"
 	"google.golang.org/grpc/encoding"
 	"google.golang.org/protobuf/proto"
+
+	enc "github.com/go-kratos/kratos/v2/encoding"
+	"github.com/go-kratos/kratos/v2/encoding/json"
 )
 
 func init() {
diff --git a/transport/grpc/interceptor.go b/transport/grpc/interceptor.go
index ccd83ea6..6cc33154 100644
--- a/transport/grpc/interceptor.go
+++ b/transport/grpc/interceptor.go
@@ -3,11 +3,12 @@ package grpc
 import (
 	"context"
 
+	"google.golang.org/grpc"
+	grpcmd "google.golang.org/grpc/metadata"
+
 	ic "github.com/go-kratos/kratos/v2/internal/context"
 	"github.com/go-kratos/kratos/v2/middleware"
 	"github.com/go-kratos/kratos/v2/transport"
-	"google.golang.org/grpc"
-	grpcmd "google.golang.org/grpc/metadata"
 )
 
 // unaryServerInterceptor is a gRPC unary server interceptor
diff --git a/transport/grpc/transport.go b/transport/grpc/transport.go
index 866228d1..50ca5c91 100644
--- a/transport/grpc/transport.go
+++ b/transport/grpc/transport.go
@@ -1,9 +1,10 @@
 package grpc
 
 import (
+	"google.golang.org/grpc/metadata"
+
 	"github.com/go-kratos/kratos/v2/selector"
 	"github.com/go-kratos/kratos/v2/transport"
-	"google.golang.org/grpc/metadata"
 )
 
 var _ transport.Transporter = (*Transport)(nil)
diff --git a/transport/http/binding/encode.go b/transport/http/binding/encode.go
index 122ec1db..72afd508 100644
--- a/transport/http/binding/encode.go
+++ b/transport/http/binding/encode.go
@@ -4,11 +4,12 @@ import (
 	"reflect"
 	"regexp"
 
-	"github.com/go-kratos/kratos/v2/encoding/form"
 	"google.golang.org/protobuf/proto"
+
+	"github.com/go-kratos/kratos/v2/encoding/form"
 )
 
-var reg = regexp.MustCompile(`/{[\\.\w]+}`)
+var reg = regexp.MustCompile(`{[\\.\w]+}`)
 
 // EncodeURL encode proto message to url path.
 func EncodeURL(pathTemplate string, msg interface{}, needQuery bool) string {
@@ -22,10 +23,10 @@ func EncodeURL(pathTemplate string, msg interface{}, needQuery bool) string {
 		//if len(in) < 4 { //nolint:gomnd // **  explain the 4 number here :-) **
 		//	return in
 		//}
-		key := in[2 : len(in)-1]
+		key := in[1 : len(in)-1]
 		value := queryParams.Get(key)
 		pathParams[key] = struct{}{}
-		return "/" + value
+		return value
 	})
 	if !needQuery {
 		if v, ok := msg.(proto.Message); ok {
diff --git a/transport/http/codec.go b/transport/http/codec.go
index 20b1a8ec..da1b13e0 100644
--- a/transport/http/codec.go
+++ b/transport/http/codec.go
@@ -4,10 +4,14 @@ import (
 	"fmt"
 	"io"
 	"net/http"
+	"net/url"
 
 	"github.com/go-kratos/kratos/v2/encoding"
 	"github.com/go-kratos/kratos/v2/errors"
 	"github.com/go-kratos/kratos/v2/internal/httputil"
+	"github.com/go-kratos/kratos/v2/transport/http/binding"
+
+	"github.com/gorilla/mux"
 )
 
 // SupportPackageIsVersion1 These constants should not be referenced from any other code.
@@ -37,6 +41,21 @@ type EncodeResponseFunc func(http.ResponseWriter, *http.Request, interface{}) er
 // EncodeErrorFunc is encode error func.
 type EncodeErrorFunc func(http.ResponseWriter, *http.Request, error)
 
+// DefaultRequestVars decodes the request vars to object.
+func DefaultRequestVars(r *http.Request, v interface{}) error {
+	raws := mux.Vars(r)
+	vars := make(url.Values, len(raws))
+	for k, v := range raws {
+		vars[k] = []string{v}
+	}
+	return binding.BindQuery(vars, v)
+}
+
+// DefaultRequestQuery decodes the request vars to object.
+func DefaultRequestQuery(r *http.Request, v interface{}) error {
+	return binding.BindQuery(r.URL.Query(), v)
+}
+
 // DefaultRequestDecoder decodes the request body to object.
 func DefaultRequestDecoder(r *http.Request, v interface{}) error {
 	codec, ok := CodecForRequest(r, "Content-Type")
diff --git a/transport/http/context.go b/transport/http/context.go
index f65e03fb..ab9a1d39 100644
--- a/transport/http/context.go
+++ b/transport/http/context.go
@@ -9,10 +9,11 @@ import (
 	"net/url"
 	"time"
 
+	"github.com/gorilla/mux"
+
 	"github.com/go-kratos/kratos/v2/middleware"
 	"github.com/go-kratos/kratos/v2/transport"
 	"github.com/go-kratos/kratos/v2/transport/http/binding"
-	"github.com/gorilla/mux"
 )
 
 var _ Context = (*wrapper)(nil)
@@ -95,9 +96,9 @@ func (c *wrapper) Middleware(h middleware.Handler) middleware.Handler {
 	}
 	return middleware.Chain(c.router.srv.middleware.Match(c.req.URL.Path)...)(h)
 }
-func (c *wrapper) Bind(v interface{}) error      { return c.router.srv.dec(c.req, v) }
-func (c *wrapper) BindVars(v interface{}) error  { return binding.BindQuery(c.Vars(), v) }
-func (c *wrapper) BindQuery(v interface{}) error { return binding.BindQuery(c.Query(), v) }
+func (c *wrapper) Bind(v interface{}) error      { return c.router.srv.decBody(c.req, v) }
+func (c *wrapper) BindVars(v interface{}) error  { return c.router.srv.decVars(c.req, v) }
+func (c *wrapper) BindQuery(v interface{}) error { return c.router.srv.decQuery(c.req, v) }
 func (c *wrapper) BindForm(v interface{}) error  { return binding.BindForm(c.req, v) }
 func (c *wrapper) Returns(v interface{}, err error) error {
 	if err != nil {
diff --git a/transport/http/server.go b/transport/http/server.go
index db7d0a72..165bb99b 100644
--- a/transport/http/server.go
+++ b/transport/http/server.go
@@ -70,10 +70,24 @@ func Filter(filters ...FilterFunc) ServerOption {
 	}
 }
 
+// RequestVarsDecoder with request decoder.
+func RequestVarsDecoder(dec DecodeRequestFunc) ServerOption {
+	return func(o *Server) {
+		o.decVars = dec
+	}
+}
+
+// RequestQueryDecoder with request decoder.
+func RequestQueryDecoder(dec DecodeRequestFunc) ServerOption {
+	return func(o *Server) {
+		o.decQuery = dec
+	}
+}
+
 // RequestDecoder with request decoder.
 func RequestDecoder(dec DecodeRequestFunc) ServerOption {
 	return func(o *Server) {
-		o.dec = dec
+		o.decBody = dec
 	}
 }
 
@@ -114,6 +128,13 @@ func Listener(lis net.Listener) ServerOption {
 	}
 }
 
+// PathPrefix with mux's PathPrefix, router will replaced by a subrouter that start with prefix.
+func PathPrefix(prefix string) ServerOption {
+	return func(s *Server) {
+		s.router = s.router.PathPrefix(prefix).Subrouter()
+	}
+}
+
 // Server is an HTTP server wrapper.
 type Server struct {
 	*http.Server
@@ -126,7 +147,9 @@ type Server struct {
 	timeout     time.Duration
 	filters     []FilterFunc
 	middleware  matcher.Matcher
-	dec         DecodeRequestFunc
+	decVars     DecodeRequestFunc
+	decQuery    DecodeRequestFunc
+	decBody     DecodeRequestFunc
 	enc         EncodeResponseFunc
 	ene         EncodeErrorFunc
 	strictSlash bool
@@ -140,15 +163,18 @@ func NewServer(opts ...ServerOption) *Server {
 		address:     ":0",
 		timeout:     1 * time.Second,
 		middleware:  matcher.New(),
-		dec:         DefaultRequestDecoder,
+		decVars:     DefaultRequestVars,
+		decQuery:    DefaultRequestQuery,
+		decBody:     DefaultRequestDecoder,
 		enc:         DefaultResponseEncoder,
 		ene:         DefaultErrorEncoder,
 		strictSlash: true,
+		router:      mux.NewRouter(),
 	}
 	for _, o := range opts {
 		o(srv)
 	}
-	srv.router = mux.NewRouter().StrictSlash(srv.strictSlash)
+	srv.router.StrictSlash(srv.strictSlash)
 	srv.router.NotFoundHandler = http.DefaultServeMux
 	srv.router.MethodNotAllowedHandler = http.DefaultServeMux
 	srv.router.Use(srv.filter())
diff --git a/transport/http/transport.go b/transport/http/transport.go
index e7f53f6d..32f054ed 100644
--- a/transport/http/transport.go
+++ b/transport/http/transport.go
@@ -70,6 +70,16 @@ func SetOperation(ctx context.Context, op string) {
 	}
 }
 
+// RequestFromServerContext returns request from context.
+func RequestFromServerContext(ctx context.Context) (*http.Request, bool) {
+	if tr, ok := transport.FromServerContext(ctx); ok {
+		if tr, ok := tr.(*Transport); ok {
+			return tr.request, true
+		}
+	}
+	return nil, false
+}
+
 type headerCarrier http.Header
 
 // Get returns the value associated with the passed key.
diff --git a/version.go b/version.go
index d0afa603..2c8d6f46 100644
--- a/version.go
+++ b/version.go
@@ -1,4 +1,4 @@
 package kratos
 
 // Release is the current kratos version.
-const Release = "v2.5.0"
+const Release = "v2.5.1"


Test patch:
diff --git a/app_test.go b/app_test.go
index aa0a5ef7..2b8c8c9d 100644
--- a/app_test.go
+++ b/app_test.go
@@ -2,7 +2,7 @@ package kratos
 
 import (
 	"context"
-	"fmt"
+	"errors"
 	"net/url"
 	"reflect"
 	"sync"
@@ -21,7 +21,7 @@ type mockRegistry struct {
 
 func (r *mockRegistry) Register(ctx context.Context, service *registry.ServiceInstance) error {
 	if service == nil || service.ID == "" {
-		return fmt.Errorf("no service id")
+		return errors.New("no service id")
 	}
 	r.lk.Lock()
 	defer r.lk.Unlock()
@@ -34,7 +34,7 @@ func (r *mockRegistry) Deregister(ctx context.Context, service *registry.Service
 	r.lk.Lock()
 	defer r.lk.Unlock()
 	if r.service[service.ID] == nil {
-		return fmt.Errorf("deregister service not found")
+		return errors.New("deregister service not found")
 	}
 	delete(r.service, service.ID)
 	return nil
diff --git a/config/file/file_test.go b/config/file/file_test.go
index d3c55ad3..0eb2b24f 100644
--- a/config/file/file_test.go
+++ b/config/file/file_test.go
@@ -208,7 +208,7 @@ func TestConfig(t *testing.T) {
 func testConfig(t *testing.T, c config.Config) {
 	expected := map[string]interface{}{
 		"test.settings.int_key":      int64(1000),
-		"test.settings.float_key":    float64(1000.1),
+		"test.settings.float_key":    1000.1,
 		"test.settings.string_key":   "string_value",
 		"test.settings.duration_key": time.Duration(10000),
 		"test.server.addr":           "127.0.0.1",
diff --git a/config/value_test.go b/config/value_test.go
index 9f674538..68558bf8 100644
--- a/config/value_test.go
+++ b/config/value_test.go
@@ -70,7 +70,7 @@ func Test_atomicValue_Int(t *testing.T) {
 }
 
 func Test_atomicValue_Float(t *testing.T) {
-	vlist := []interface{}{"123123.1", float64(123123.1)}
+	vlist := []interface{}{"123123.1", 123123.1}
 	for _, x := range vlist {
 		v := atomicValue{}
 		v.Store(x)
@@ -78,7 +78,7 @@ func Test_atomicValue_Float(t *testing.T) {
 		if err != nil {
 			t.Fatal(`err is not nil`)
 		}
-		if b != float64(123123.1) {
+		if b != 123123.1 {
 			t.Fatal(`b is not equal to 123123.1`)
 		}
 	}
diff --git a/contrib/config/consul/config_test.go b/contrib/config/consul/config_test.go
index a82a2036..adb3c27c 100644
--- a/contrib/config/consul/config_test.go
+++ b/contrib/config/consul/config_test.go
@@ -5,8 +5,9 @@ import (
 	"testing"
 	"time"
 
-	"github.com/go-kratos/kratos/v2/config"
 	"github.com/hashicorp/consul/api"
+
+	"github.com/go-kratos/kratos/v2/config"
 )
 
 const testPath = "kratos/test/config"
diff --git a/contrib/log/aliyun/aliyun_test.go b/contrib/log/aliyun/aliyun_test.go
index 1ceafc32..e8e2624f 100644
--- a/contrib/log/aliyun/aliyun_test.go
+++ b/contrib/log/aliyun/aliyun_test.go
@@ -1,6 +1,7 @@
 package aliyun
 
 import (
+	"math"
 	"testing"
 
 	"github.com/go-kratos/kratos/v2/log"
@@ -92,4 +93,40 @@ func TestLog(t *testing.T) {
 	if err != nil {
 		t.Errorf("Log() returns error:%v", err)
 	}
+	err = logger.Log(log.LevelDebug, true, 0)
+	if err != nil {
+		t.Errorf("Log() returns error:%v", err)
+	}
+}
+
+func TestToString(t *testing.T) {
+	tests := []struct {
+		in  interface{}
+		out string
+	}{
+		{math.MaxFloat64, "17976931348623157000000000000000000000000000000000000" +
+			"000000000000000000000000000000000000000000000000000000000000000000000000000" +
+			"000000000000000000000000000000000000000000000000000000000000000000000000000" +
+			"000000000000000000000000000000000000000000000000000000000000000000000000000" +
+			"0000000000000000000000000000000"},
+		{math.MaxFloat32, "340282346638528860000000000000000000000"},
+		{1<<((32<<(^uint(0)>>63))-1) - 1, "9223372036854775807"},
+		{uint(1<<(32<<(^uint(0)>>63)) - 1), "-1"},
+		{math.MaxInt8, "127"},
+		{math.MaxUint8, "255"},
+		{math.MaxInt16, "32767"},
+		{math.MaxUint16, "65535"},
+		{math.MaxInt32, "2147483647"},
+		{math.MaxUint32, "4294967295"},
+		{math.MaxInt64, "9223372036854775807"},
+		{uint64(math.MaxUint64), "18446744073709551615"},
+		{"abc", "abc"},
+		{false, "false"},
+		{[]byte("abc"), "abc"},
+	}
+	for _, test := range tests {
+		if toString(test.in) != test.out {
+			t.Fatalf("want: %s, got: %s", test.out, toString(test.in))
+		}
+	}
 }
diff --git a/contrib/log/fluent/fluent_test.go b/contrib/log/fluent/fluent_test.go
index 5b7b3e17..41f7080d 100644
--- a/contrib/log/fluent/fluent_test.go
+++ b/contrib/log/fluent/fluent_test.go
@@ -11,18 +11,23 @@ import (
 )
 
 func TestMain(m *testing.M) {
+	listener := func(ln net.Listener) {
+		conn, err := ln.Accept()
+		if err != nil {
+			return
+		}
+		defer conn.Close()
+		_, err = io.ReadAll(conn)
+		if err != nil {
+			return
+		}
+	}
+
 	if ln, err := net.Listen("tcp", ":24224"); err == nil {
 		defer ln.Close()
 		go func() {
 			for {
-				conn, err := ln.Accept()
-				if err != nil {
-					return
-				}
-				defer conn.Close()
-				if _, err = io.ReadAll(conn); err != nil {
-					continue
-				}
+				listener(ln)
 			}
 		}()
 	}
diff --git a/contrib/log/logrus/logrus_test.go b/contrib/log/logrus/logrus_test.go
index 50b7a99b..45fe9da2 100644
--- a/contrib/log/logrus/logrus_test.go
+++ b/contrib/log/logrus/logrus_test.go
@@ -5,8 +5,9 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/go-kratos/kratos/v2/log"
 	"github.com/sirupsen/logrus"
+
+	"github.com/go-kratos/kratos/v2/log"
 )
 
 func TestLoggerLog(t *testing.T) {
diff --git a/contrib/registry/consul/registry_test.go b/contrib/registry/consul/registry_test.go
index 483faf1a..6a1523c4 100644
--- a/contrib/registry/consul/registry_test.go
+++ b/contrib/registry/consul/registry_test.go
@@ -8,8 +8,9 @@ import (
 	"testing"
 	"time"
 
-	"github.com/go-kratos/kratos/v2/registry"
 	"github.com/hashicorp/consul/api"
+
+	"github.com/go-kratos/kratos/v2/registry"
 )
 
 func tcpServer(t *testing.T, lis net.Listener) {
diff --git a/contrib/registry/etcd/registry_test.go b/contrib/registry/etcd/registry_test.go
index 844d67ff..8fcecf94 100644
--- a/contrib/registry/etcd/registry_test.go
+++ b/contrib/registry/etcd/registry_test.go
@@ -8,8 +8,9 @@ import (
 
 	"google.golang.org/grpc"
 
-	"github.com/go-kratos/kratos/v2/registry"
 	clientv3 "go.etcd.io/etcd/client/v3"
+
+	"github.com/go-kratos/kratos/v2/registry"
 )
 
 func TestRegistry(t *testing.T) {
diff --git a/contrib/registry/servicecomb/registry_test.go b/contrib/registry/servicecomb/registry_test.go
index 85afe306..4b4c2549 100644
--- a/contrib/registry/servicecomb/registry_test.go
+++ b/contrib/registry/servicecomb/registry_test.go
@@ -6,8 +6,9 @@ import (
 
 	pb "github.com/go-chassis/cari/discovery"
 	"github.com/go-chassis/sc-client"
-	"github.com/go-kratos/kratos/v2/registry"
 	"github.com/gofrs/uuid"
+
+	"github.com/go-kratos/kratos/v2/registry"
 )
 
 var r *Registry
diff --git a/contrib/registry/zookeeper/register_test.go b/contrib/registry/zookeeper/register_test.go
index 131f3ee1..a6f4515e 100644
--- a/contrib/registry/zookeeper/register_test.go
+++ b/contrib/registry/zookeeper/register_test.go
@@ -6,8 +6,9 @@ import (
 	"testing"
 	"time"
 
-	"github.com/go-kratos/kratos/v2/registry"
 	"github.com/go-zookeeper/zk"
+
+	"github.com/go-kratos/kratos/v2/registry"
 )
 
 func TestRegistry_GetService(t *testing.T) {
diff --git a/encoding/xml/xml_test.go b/encoding/xml/xml_test.go
index 6c53c3dd..09e7d03b 100644
--- a/encoding/xml/xml_test.go
+++ b/encoding/xml/xml_test.go
@@ -25,7 +25,7 @@ func TestCodec_Marshal(t *testing.T) {
 		// Test value types
 		{Value: &Plain{true}, ExpectXML: `<Plain><V>true</V></Plain>`},
 		{Value: &Plain{false}, ExpectXML: `<Plain><V>false</V></Plain>`},
-		{Value: &Plain{int(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
+		{Value: &Plain{42}, ExpectXML: `<Plain><V>42</V></Plain>`},
 		{
 			Value: &NestedOrder{Field1: "C", Field2: "B", Field3: "A"},
 			ExpectXML: `<result>` +
diff --git a/middleware/auth/jwt/jwt_test.go b/middleware/auth/jwt/jwt_test.go
index 188744b0..711757bc 100644
--- a/middleware/auth/jwt/jwt_test.go
+++ b/middleware/auth/jwt/jwt_test.go
@@ -254,7 +254,7 @@ func TestServer(t *testing.T) {
 			}
 			if test.exceptErr == nil {
 				if testToken == nil {
-					t.Errorf("except testToken not nil, but got nil")
+					t.Fatal("except testToken not nil, but got nil")
 				}
 				_, ok := testToken.(jwt.MapClaims)
 				if !ok {
@@ -493,3 +493,26 @@ func TestClientMissKey(t *testing.T) {
 		}
 	})
 }
+
+func TestNewContextAndFromContext(t *testing.T) {
+	tests := []struct {
+		name   string
+		claims jwt.MapClaims
+	}{
+		{"val not nil", jwt.MapClaims{"name": "kratos"}},
+		{"val nil", nil},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			ctx := NewContext(context.Background(), test.claims)
+
+			claims, ok := FromContext(ctx)
+			if !ok {
+				t.Fatal("ctx not found authKey{}")
+			}
+			if !reflect.DeepEqual(test.claims, claims) {
+				t.Errorf(`want: %s, got: %v`, test.claims, claims)
+			}
+		})
+	}
+}
diff --git a/middleware/circuitbreaker/circuitbreaker_test.go b/middleware/circuitbreaker/circuitbreaker_test.go
index b7c2553c..611419c7 100644
--- a/middleware/circuitbreaker/circuitbreaker_test.go
+++ b/middleware/circuitbreaker/circuitbreaker_test.go
@@ -5,7 +5,7 @@ import (
 	"errors"
 	"testing"
 
-	kratos_errors "github.com/go-kratos/kratos/v2/errors"
+	kratoserrors "github.com/go-kratos/kratos/v2/errors"
 	"github.com/go-kratos/kratos/v2/internal/group"
 	"github.com/go-kratos/kratos/v2/transport"
 )
@@ -62,7 +62,7 @@ func Test_Server(t *testing.T) {
 		return "Hello valid", nil
 	}
 	nextInvalid := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return nil, kratos_errors.InternalServer("", "")
+		return nil, kratoserrors.InternalServer("", "")
 	}
 
 	ctx := transport.NewClientContext(context.Background(), &transportMock{})
diff --git a/middleware/logging/logging_test.go b/middleware/logging/logging_test.go
index 6ad1a02c..431d8901 100644
--- a/middleware/logging/logging_test.go
+++ b/middleware/logging/logging_test.go
@@ -111,7 +111,7 @@ func (d *dummyStringer) String() string {
 	return "my value"
 }
 
-func Test_extractArgs(t *testing.T) {
+func TestExtractArgs(t *testing.T) {
 	if extractArgs(&dummyStringer{field: ""}) != "my value" {
 		t.Errorf(`The stringified dummyStringer structure must be equal to "my value", %v given`, extractArgs(&dummyStringer{field: ""}))
 	}
@@ -120,3 +120,30 @@ func Test_extractArgs(t *testing.T) {
 		t.Errorf(`The stringified dummy structure must be equal to "&{field:value}", %v given`, extractArgs(&dummy{field: "value"}))
 	}
 }
+
+func TestExtractError(t *testing.T) {
+	tests := []struct {
+		name       string
+		err        error
+		wantLevel  log.Level
+		wantErrStr string
+	}{
+		{
+			"no error", nil, log.LevelInfo, "",
+		},
+		{
+			"error", errors.New("test error"), log.LevelError, "test error",
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			level, errStr := extractError(test.err)
+			if level != test.wantLevel {
+				t.Errorf("want: %d, got: %d", test.wantLevel, level)
+			}
+			if errStr != test.wantErrStr {
+				t.Errorf("want: %s, got: %s", test.wantErrStr, errStr)
+			}
+		})
+	}
+}
diff --git a/middleware/metadata/metadata_test.go b/middleware/metadata/metadata_test.go
index e46a94f5..b083f9c1 100644
--- a/middleware/metadata/metadata_test.go
+++ b/middleware/metadata/metadata_test.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"errors"
 	"net/http"
+	"reflect"
 	"testing"
 
 	"github.com/go-kratos/kratos/v2/metadata"
@@ -33,15 +34,18 @@ func (tr *testTransport) Operation() string               { return "" }
 func (tr *testTransport) RequestHeader() transport.Header { return tr.header }
 func (tr *testTransport) ReplyHeader() transport.Header   { return tr.header }
 
+var (
+	globalKey   = "x-md-global-key"
+	globalValue = "global-value"
+	localKey    = "x-md-local-key"
+	localValue  = "local-value"
+	customKey   = "x-md-local-custom"
+	customValue = "custom-value"
+	constKey    = "x-md-local-const"
+	constValue  = "x-md-local-const"
+)
+
 func TestSever(t *testing.T) {
-	var (
-		globalKey   = "x-md-global-key"
-		globalValue = "global-value"
-		localKey    = "x-md-local-key"
-		localValue  = "local-value"
-		constKey    = "x-md-local-const"
-		constValue  = "x-md-local-const"
-	)
 	hs := func(ctx context.Context, in interface{}) (interface{}, error) {
 		md, ok := metadata.FromServerContext(ctx)
 		if !ok {
@@ -75,16 +79,6 @@ func TestSever(t *testing.T) {
 }
 
 func TestClient(t *testing.T) {
-	var (
-		globalKey   = "x-md-global-key"
-		globalValue = "global-value"
-		localKey    = "x-md-local-key"
-		localValue  = "local-value"
-		customKey   = "x-md-local-custom"
-		customValue = "custom-value"
-		constKey    = "x-md-local-const"
-		constValue  = "x-md-local-const"
-	)
 	hs := func(ctx context.Context, in interface{}) (interface{}, error) {
 		tr, ok := transport.FromClientContext(ctx)
 		if !ok {
@@ -127,13 +121,52 @@ func TestClient(t *testing.T) {
 	}
 }
 
-func Test_WithPropagatedPrefix(t *testing.T) {
-	o := &options{
+func TestWithConstants(t *testing.T) {
+	md := metadata.Metadata{
+		constKey: constValue,
+	}
+	options := &options{
+		md: metadata.Metadata{
+			"override": "override",
+		},
+	}
+
+	WithConstants(md)(options)
+	if !reflect.DeepEqual(md, options.md) {
+		t.Errorf("want: %v, got: %v", md, options.md)
+	}
+}
+
+func TestOptions_WithPropagatedPrefix(t *testing.T) {
+	options := &options{
 		prefix: []string{"override"},
 	}
-	WithPropagatedPrefix("something", "another")(o)
+	prefixes := []string{"something", "another"}
 
-	if len(o.prefix) != 2 {
+	WithPropagatedPrefix(prefixes...)(options)
+	if !reflect.DeepEqual(prefixes, options.prefix) {
 		t.Error("The prefix must be overridden.")
 	}
 }
+
+func TestOptions_hasPrefix(t *testing.T) {
+	tests := []struct {
+		name    string
+		options *options
+		key     string
+		exists  bool
+	}{
+		{"exists key upper", &options{prefix: []string{"prefix"}}, "PREFIX_true", true},
+		{"exists key lower", &options{prefix: []string{"prefix"}}, "prefix_true", true},
+		{"not exists key upper", &options{prefix: []string{"prefix"}}, "false_PREFIX", false},
+		{"not exists key lower", &options{prefix: []string{"prefix"}}, "false_prefix", false},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			exists := test.options.hasPrefix(test.key)
+			if test.exists != exists {
+				t.Errorf("key: '%sr', not exists prefixs: %v", test.key, test.options.prefix)
+			}
+		})
+	}
+}
diff --git a/middleware/tracing/span_test.go b/middleware/tracing/span_test.go
index aad4614f..110dc6f5 100644
--- a/middleware/tracing/span_test.go
+++ b/middleware/tracing/span_test.go
@@ -7,13 +7,14 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/go-kratos/kratos/v2/internal/testdata/binding"
-	"github.com/go-kratos/kratos/v2/metadata"
-	"github.com/go-kratos/kratos/v2/transport"
 	"go.opentelemetry.io/otel/attribute"
 	semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
 	"go.opentelemetry.io/otel/trace"
 	"google.golang.org/grpc/peer"
+
+	"github.com/go-kratos/kratos/v2/internal/testdata/binding"
+	"github.com/go-kratos/kratos/v2/metadata"
+	"github.com/go-kratos/kratos/v2/transport"
 )
 
 func Test_parseFullMethod(t *testing.T) {
diff --git a/middleware/tracing/tracer_test.go b/middleware/tracing/tracer_test.go
index fbd51c07..af63844e 100644
--- a/middleware/tracing/tracer_test.go
+++ b/middleware/tracing/tracer_test.go
@@ -5,8 +5,9 @@ import (
 	"errors"
 	"testing"
 
-	"github.com/go-kratos/kratos/v2/internal/testdata/binding"
 	"go.opentelemetry.io/otel/trace"
+
+	"github.com/go-kratos/kratos/v2/internal/testdata/binding"
 )
 
 func Test_NewTracer(t *testing.T) {
diff --git a/middleware/tracing/tracing_test.go b/middleware/tracing/tracing_test.go
index 222a6acc..b95771ab 100644
--- a/middleware/tracing/tracing_test.go
+++ b/middleware/tracing/tracing_test.go
@@ -7,11 +7,12 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/go-kratos/kratos/v2/log"
-	"github.com/go-kratos/kratos/v2/transport"
 	"go.opentelemetry.io/otel/propagation"
 	tracesdk "go.opentelemetry.io/otel/sdk/trace"
 	"go.opentelemetry.io/otel/trace"
+
+	"github.com/go-kratos/kratos/v2/log"
+	"github.com/go-kratos/kratos/v2/transport"
 )
 
 var _ transport.Transporter = (*mockTransport)(nil)
diff --git a/middleware/validate/validate_test.go b/middleware/validate/validate_test.go
index f1597820..34fc3349 100644
--- a/middleware/validate/validate_test.go
+++ b/middleware/validate/validate_test.go
@@ -2,10 +2,10 @@ package validate
 
 import (
 	"context"
-	"fmt"
+	"errors"
 	"testing"
 
-	"github.com/go-kratos/kratos/v2/errors"
+	kratoserrors "github.com/go-kratos/kratos/v2/errors"
 	"github.com/go-kratos/kratos/v2/middleware"
 )
 
@@ -18,7 +18,7 @@ type protoVali struct {
 
 func (v protoVali) Validate() error {
 	if v.name == "" || v.age < 0 {
-		return fmt.Errorf("err")
+		return errors.New("err")
 	}
 	return nil
 }
@@ -35,7 +35,7 @@ func TestTable(t *testing.T) {
 		t.Run(test.name, func(t *testing.T) {
 			v := Validator()(mock)
 			_, err := v(context.Background(), test)
-			if want, have := test.isErr, errors.IsBadRequest(err); want != have {
+			if want, have := test.isErr, kratoserrors.IsBadRequest(err); want != have {
 				t.Errorf("fail data %v, want %v, have %v", test, want, have)
 			}
 		})
diff --git a/transport/grpc/balancer_test.go b/transport/grpc/balancer_test.go
index 5b700264..2dbb53bb 100644
--- a/transport/grpc/balancer_test.go
+++ b/transport/grpc/balancer_test.go
@@ -5,8 +5,9 @@ import (
 	"reflect"
 	"testing"
 
-	"github.com/go-kratos/kratos/v2/selector"
 	"google.golang.org/grpc/metadata"
+
+	"github.com/go-kratos/kratos/v2/selector"
 )
 
 func TestTrailer(t *testing.T) {
diff --git a/transport/grpc/client_test.go b/transport/grpc/client_test.go
index d2540a7d..7ad55368 100644
--- a/transport/grpc/client_test.go
+++ b/transport/grpc/client_test.go
@@ -7,9 +7,10 @@ import (
 	"testing"
 	"time"
 
+	"google.golang.org/grpc"
+
 	"github.com/go-kratos/kratos/v2/middleware"
 	"github.com/go-kratos/kratos/v2/registry"
-	"google.golang.org/grpc"
 )
 
 func TestWithEndpoint(t *testing.T) {
diff --git a/transport/grpc/resolver/direct/builder_test.go b/transport/grpc/resolver/direct/builder_test.go
index 1cd6bf40..82cd8cd1 100644
--- a/transport/grpc/resolver/direct/builder_test.go
+++ b/transport/grpc/resolver/direct/builder_test.go
@@ -1,7 +1,7 @@
 package direct
 
 import (
-	"fmt"
+	"errors"
 	"reflect"
 	"testing"
 
@@ -22,7 +22,7 @@ type mockConn struct {
 
 func (m *mockConn) UpdateState(resolver.State) error {
 	if m.needUpdateStateErr {
-		return fmt.Errorf("mock test needUpdateStateErr")
+		return errors.New("mock test needUpdateStateErr")
 	}
 	return nil
 }
diff --git a/transport/grpc/resolver/discovery/builder_test.go b/transport/grpc/resolver/discovery/builder_test.go
index 770f12f1..664b5d44 100644
--- a/transport/grpc/resolver/discovery/builder_test.go
+++ b/transport/grpc/resolver/discovery/builder_test.go
@@ -7,9 +7,10 @@ import (
 	"testing"
 	"time"
 
-	"github.com/go-kratos/kratos/v2/registry"
 	"google.golang.org/grpc/resolver"
 	"google.golang.org/grpc/serviceconfig"
+
+	"github.com/go-kratos/kratos/v2/registry"
 )
 
 func TestWithInsecure(t *testing.T) {
diff --git a/transport/grpc/resolver/discovery/resolver_test.go b/transport/grpc/resolver/discovery/resolver_test.go
index 33d9fc27..39ae400e 100644
--- a/transport/grpc/resolver/discovery/resolver_test.go
+++ b/transport/grpc/resolver/discovery/resolver_test.go
@@ -7,8 +7,9 @@ import (
 	"testing"
 	"time"
 
-	"github.com/go-kratos/kratos/v2/registry"
 	"google.golang.org/grpc/resolver"
+
+	"github.com/go-kratos/kratos/v2/registry"
 )
 
 type testClientConn struct {
diff --git a/transport/grpc/server_test.go b/transport/grpc/server_test.go
index fd1ae675..4db44fe9 100644
--- a/transport/grpc/server_test.go
+++ b/transport/grpc/server_test.go
@@ -11,12 +11,13 @@ import (
 	"testing"
 	"time"
 
+	"google.golang.org/grpc"
+
 	"github.com/go-kratos/kratos/v2/errors"
 	"github.com/go-kratos/kratos/v2/internal/matcher"
 	pb "github.com/go-kratos/kratos/v2/internal/testdata/helloworld"
 	"github.com/go-kratos/kratos/v2/middleware"
 	"github.com/go-kratos/kratos/v2/transport"
-	"google.golang.org/grpc"
 )
 
 // server is used to implement helloworld.GreeterServer.
diff --git a/transport/http/binding/encode_test.go b/transport/http/binding/encode_test.go
index 16c7cf0e..7e8286c9 100644
--- a/transport/http/binding/encode_test.go
+++ b/transport/http/binding/encode_test.go
@@ -1,96 +1,139 @@
 package binding
 
 import (
-	"fmt"
 	"testing"
 
-	"github.com/go-kratos/kratos/v2/internal/testdata/binding"
 	"google.golang.org/protobuf/types/known/fieldmaskpb"
+
+	"github.com/go-kratos/kratos/v2/internal/testdata/binding"
 )
 
 func TestProtoPath(t *testing.T) {
-	url := EncodeURL("http://helloworld.Greeter/helloworld/{name}/sub/{sub.naming}", &binding.HelloRequest{
-		Name: "test", Sub: &binding.Sub{Name: "2233!!!"},
-	}, false)
-	if url != `http://helloworld.Greeter/helloworld/test/sub/2233!!!` {
-		t.Fatalf("proto path not expected!actual: %s ", url)
-	}
-	url = EncodeURL("http://helloworld.Greeter/helloworld/{name}/sub/{sub.naming}", nil, false)
-	fmt.Println(url)
-	if url != "http://helloworld.Greeter/helloworld/{name}/sub/{sub.naming}" {
-		t.Fatalf("proto path not expected!actual: %s ", url)
-	}
-	url = EncodeURL("http://helloworld.Greeter/helloworld/{}/sub/{sub.naming}", &binding.HelloRequest{
-		Name: "test", Sub: &binding.Sub{Name: "hello"},
-	}, false)
-	fmt.Println(url)
-	if url != "http://helloworld.Greeter/helloworld/{}/sub/hello" {
-		t.Fatalf("proto path not expected!actual: %s ", url)
-	}
-	url = EncodeURL("http://helloworld.Greeter/helloworld/{}/sub/{sub.name.cc}", &binding.HelloRequest{
-		Name: "test", Sub: &binding.Sub{Name: "hello"},
-	}, false)
-	fmt.Println(url)
-	if url != "http://helloworld.Greeter/helloworld/{}/sub/" {
-		t.Fatalf("proto path not expected!actual: %s ", url)
-	}
-
-	url = EncodeURL(
-		"http://helloworld.Greeter/helloworld/{}/sub/{test_repeated}",
-		&binding.HelloRequest{
-			Name: "test", Sub: &binding.Sub{Name: "hello"},
-			TestRepeated: []string{"123", "456"},
-		},
-		false,
-	)
-	fmt.Println(url)
-	if url != "http://helloworld.Greeter/helloworld/{}/sub/123" {
-		t.Fatalf("proto path not expected!actual: %s ", url)
-	}
-
-	url = EncodeURL("http://helloworld.Greeter/helloworld/{name}/sub/{sub.naming}", &binding.HelloRequest{
-		Name: "test", Sub: &binding.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", &binding.HelloRequest{
-		Name: "test", Sub: &binding.Sub{Name: "2233!!!"},
-	}, false)
-	fmt.Println(url)
-	if url != `http://helloworld.Greeter/helloworld/sub` {
-		t.Fatalf("proto path not expected!actual: %s ", url)
-	}
-
-	url = EncodeURL("http://helloworld.Greeter/helloworld/{name}/sub/{sub.name}", &binding.HelloRequest{Name: "test"}, false)
-	fmt.Println(url)
-	if url != `http://helloworld.Greeter/helloworld/test/sub/` {
-		t.Fatalf("proto path not expected!actual: %s ", url)
-	}
-
-	url = EncodeURL("http://helloworld.Greeter/helloworld/{name}/sub/{sub.name}", &binding.HelloRequest{Name: "test"}, false)
-	fmt.Println(url)
-	if url != `http://helloworld.Greeter/helloworld/test/sub/` {
-		t.Fatalf("proto path not expected!actual: %s ", url)
-	}
-
-	url = EncodeURL("http://helloworld.Greeter/helloworld/{name}/sub", &binding.HelloRequest{
-		Name: "go",
-		Sub:  &binding.Sub{Name: "kratos"},
-	}, true)
-	fmt.Println(url)
-	if url != `http://helloworld.Greeter/helloworld/go/sub?sub.naming=kratos` {
-		t.Fatalf("proto path not expected!actual: %s ", url)
+	tests := []struct {
+		pathTemplate string
+		request      *binding.HelloRequest
+		needQuery    bool
+		want         string
+	}{
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/{name}/sub/{sub.naming}",
+			request:      &binding.HelloRequest{Name: "test", Sub: &binding.Sub{Name: "2233!!!!"}},
+			needQuery:    false,
+			want:         "http://helloworld.Greeter/helloworld/test/sub/2233!!!!",
+		},
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/{name}/sub/{sub.naming}",
+			request:      nil,
+			needQuery:    false,
+			want:         "http://helloworld.Greeter/helloworld/{name}/sub/{sub.naming}",
+		},
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/{}/sub/{sub.naming}",
+			request:      &binding.HelloRequest{Name: "test", Sub: &binding.Sub{Name: "hello"}},
+			needQuery:    false,
+			want:         "http://helloworld.Greeter/helloworld/{}/sub/hello",
+		},
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/{}/sub/{sub.naming}",
+			request:      &binding.HelloRequest{Name: "test", Sub: &binding.Sub{Name: "hello"}},
+			needQuery:    false,
+			want:         "http://helloworld.Greeter/helloworld/{}/sub/hello",
+		},
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/{}/sub/{sub.name.cc}",
+			request:      &binding.HelloRequest{Name: "test", Sub: &binding.Sub{Name: "hello"}},
+			needQuery:    false,
+			want:         "http://helloworld.Greeter/helloworld/{}/sub/",
+		},
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/{}/sub/{test_repeated}",
+			request:      &binding.HelloRequest{Name: "test", Sub: &binding.Sub{Name: "hello"}, TestRepeated: []string{"123", "456"}},
+			needQuery:    false,
+			want:         "http://helloworld.Greeter/helloworld/{}/sub/123",
+		},
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/{name}/sub/{sub.naming}",
+			request:      &binding.HelloRequest{Name: "test", Sub: &binding.Sub{Name: "5566!!!"}},
+			needQuery:    false,
+			want:         "http://helloworld.Greeter/helloworld/test/sub/5566!!!",
+		},
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/sub",
+			request:      &binding.HelloRequest{Name: "test", Sub: &binding.Sub{Name: "2233!!!"}},
+			needQuery:    false,
+			want:         "http://helloworld.Greeter/helloworld/sub",
+		},
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/{name}/sub/{sub.name}",
+			request:      &binding.HelloRequest{Name: "test"},
+			needQuery:    false,
+			want:         "http://helloworld.Greeter/helloworld/test/sub/",
+		},
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/{name}/sub/{sub.name}",
+			request:      &binding.HelloRequest{Name: "test"},
+			needQuery:    false,
+			want:         "http://helloworld.Greeter/helloworld/test/sub/",
+		},
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/{name}/sub",
+			request:      &binding.HelloRequest{Name: "go", Sub: &binding.Sub{Name: "kratos"}},
+			needQuery:    true,
+			want:         "http://helloworld.Greeter/helloworld/go/sub?sub.naming=kratos",
+		},
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/sub/{sub.naming}",
+			request:      &binding.HelloRequest{Sub: &binding.Sub{Name: "kratos"}, UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"name", "sub.naming"}}},
+			needQuery:    false,
+			want:         "http://helloworld.Greeter/helloworld/sub/kratos?updateMask=name,sub.naming",
+		},
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/sub/[{sub.naming}]",
+			request:      &binding.HelloRequest{Sub: &binding.Sub{Name: "kratos"}},
+			needQuery:    false,
+			want:         "http://helloworld.Greeter/helloworld/sub/[kratos]",
+		},
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/[{name}]/sub/[{sub.naming}]",
+			request:      &binding.HelloRequest{Name: "test", Sub: &binding.Sub{Name: "kratos"}},
+			needQuery:    false,
+			want:         "http://helloworld.Greeter/helloworld/[test]/sub/[kratos]",
+		},
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/[{}]/sub/[{sub.naming}]",
+			request:      &binding.HelloRequest{Sub: &binding.Sub{Name: "kratos"}},
+			needQuery:    false,
+			want:         "http://helloworld.Greeter/helloworld/[{}]/sub/[kratos]",
+		},
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/[{}]/sub/[{sub.naming}]/{[]}",
+			request:      &binding.HelloRequest{Sub: &binding.Sub{Name: "kratos"}},
+			needQuery:    false,
+			want:         "http://helloworld.Greeter/helloworld/[{}]/sub/[kratos]/{[]}",
+		},
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/{[sub]}/[{sub.naming}]",
+			request:      &binding.HelloRequest{Sub: &binding.Sub{Name: "kratos"}},
+			needQuery:    false,
+			want:         "http://helloworld.Greeter/helloworld/{[sub]}/[kratos]",
+		},
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/{[name]}/[{sub.naming}]",
+			request:      &binding.HelloRequest{Name: "test", Sub: &binding.Sub{Name: "kratos"}},
+			needQuery:    false,
+			want:         "http://helloworld.Greeter/helloworld/{[name]}/[kratos]",
+		},
+		{
+			pathTemplate: "http://helloworld.Greeter/helloworld/{}/[]/[{sub.naming}]",
+			request:      &binding.HelloRequest{Sub: &binding.Sub{Name: "kratos"}},
+			needQuery:    false,
+			want:         "http://helloworld.Greeter/helloworld/{}/[]/[kratos]",
+		},
 	}
 
-	url = EncodeURL("http://helloworld.Greeter/helloworld/sub/{sub.naming}", &binding.HelloRequest{
-		Sub:        &binding.Sub{Name: "kratos"},
-		UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"name", "sub.naming"}},
-	}, false)
-	fmt.Println(url)
-	if url != `http://helloworld.Greeter/helloworld/sub/kratos?updateMask=name,sub.naming` {
-		t.Fatalf("proto path not expected!actual: %s ", url)
+	for _, test := range tests {
+		if EncodeURL(test.pathTemplate, test.request, test.needQuery) != test.want {
+			t.Fatalf("want: %s, got: %s", test.want, EncodeURL(test.pathTemplate, test.request, test.needQuery))
+		}
 	}
 }
diff --git a/transport/http/client_test.go b/transport/http/client_test.go
index 4ee00456..ab8031dd 100644
--- a/transport/http/client_test.go
+++ b/transport/http/client_test.go
@@ -33,7 +33,7 @@ type mockCallOption struct {
 
 func (x *mockCallOption) before(info *callInfo) error {
 	if x.needErr {
-		return fmt.Errorf("option need return err")
+		return errors.New("option need return err")
 	}
 	return nil
 }
@@ -357,7 +357,7 @@ func TestNewClient(t *testing.T) {
 		t.Error("err should be equal to callOption err")
 	}
 	client.opts.encoder = func(ctx context.Context, contentType string, in interface{}) (body []byte, err error) {
-		return nil, fmt.Errorf("mock test encoder error")
+		return nil, errors.New("mock test encoder error")
 	}
 	err = client.Invoke(context.Background(), "POST", "/go", map[string]string{"name": "kratos"}, nil, EmptyCallOption{})
 	if err == nil {
diff --git a/transport/http/context_test.go b/transport/http/context_test.go
index 3b7466bf..daccccd9 100644
--- a/transport/http/context_test.go
+++ b/transport/http/context_test.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"errors"
-	"fmt"
 	"net/http"
 	"net/http/httptest"
 	"net/url"
@@ -13,9 +12,11 @@ import (
 	"time"
 )
 
+var testRouter = &Router{srv: NewServer()}
+
 func TestContextHeader(t *testing.T) {
 	w := wrapper{
-		router: nil,
+		router: testRouter,
 		req:    &http.Request{Header: map[string][]string{"name": {"kratos"}}},
 		res:    nil,
 		w:      responseWriter{},
@@ -28,7 +29,7 @@ func TestContextHeader(t *testing.T) {
 
 func TestContextForm(t *testing.T) {
 	w := wrapper{
-		router: nil,
+		router: testRouter,
 		req:    &http.Request{Header: map[string][]string{"name": {"kratos"}}, Method: "POST"},
 		res:    nil,
 		w:      responseWriter{},
@@ -39,7 +40,7 @@ func TestContextForm(t *testing.T) {
 	}
 
 	w = wrapper{
-		router: nil,
+		router: testRouter,
 		req:    &http.Request{Form: map[string][]string{"name": {"kratos"}}},
 		res:    nil,
 		w:      responseWriter{},
@@ -52,7 +53,7 @@ func TestContextForm(t *testing.T) {
 
 func TestContextQuery(t *testing.T) {
 	w := wrapper{
-		router: nil,
+		router: testRouter,
 		req:    &http.Request{URL: &url.URL{Scheme: "https", Host: "github.com", Path: "go-kratos/kratos", RawQuery: "page=1"}, Method: "POST"},
 		res:    nil,
 		w:      responseWriter{},
@@ -66,7 +67,7 @@ func TestContextQuery(t *testing.T) {
 func TestContextRequest(t *testing.T) {
 	req := &http.Request{Method: "POST"}
 	w := wrapper{
-		router: nil,
+		router: testRouter,
 		req:    req,
 		res:    nil,
 		w:      responseWriter{},
@@ -92,7 +93,7 @@ func TestContextResponse(t *testing.T) {
 	if err != nil {
 		t.Errorf("expected %v, got %v", nil, err)
 	}
-	needErr := fmt.Errorf("some error")
+	needErr := errors.New("some error")
 	err = w.Returns(map[string]string{}, needErr)
 	if !errors.Is(err, needErr) {
 		t.Errorf("expected %v, got %v", needErr, err)
@@ -101,7 +102,7 @@ func TestContextResponse(t *testing.T) {
 
 func TestContextBindQuery(t *testing.T) {
 	w := wrapper{
-		router: nil,
+		router: testRouter,
 		req:    &http.Request{URL: &url.URL{Scheme: "https", Host: "go-kratos-dev", RawQuery: "page=2"}},
 		res:    nil,
 		w:      responseWriter{},
@@ -121,7 +122,7 @@ func TestContextBindQuery(t *testing.T) {
 
 func TestContextBindForm(t *testing.T) {
 	w := wrapper{
-		router: nil,
+		router: testRouter,
 		req:    &http.Request{URL: &url.URL{Scheme: "https", Host: "go-kratos-dev"}, Form: map[string][]string{"page": {"2"}}},
 		res:    nil,
 		w:      responseWriter{},
@@ -142,7 +143,7 @@ func TestContextBindForm(t *testing.T) {
 func TestContextResponseReturn(t *testing.T) {
 	writer := httptest.NewRecorder()
 	w := wrapper{
-		router: nil,
+		router: testRouter,
 		req:    nil,
 		res:    writer,
 		w:      responseWriter{},
@@ -175,7 +176,7 @@ func TestContextCtx(t *testing.T) {
 	req := &http.Request{Method: "POST"}
 	req = req.WithContext(ctx)
 	w := wrapper{
-		router: &Router{srv: &Server{enc: DefaultResponseEncoder}},
+		router: testRouter,
 		req:    req,
 		res:    nil,
 		w:      responseWriter{},
diff --git a/transport/http/resolver_test.go b/transport/http/resolver_test.go
index 27473d12..e95d8850 100644
--- a/transport/http/resolver_test.go
+++ b/transport/http/resolver_test.go
@@ -73,7 +73,7 @@ const errServiceName = "needErr"
 
 func (d *mockDiscoveries) Watch(ctx context.Context, serviceName string) (registry.Watcher, error) {
 	if serviceName == errServiceName {
-		return nil, fmt.Errorf("mock test service name watch err")
+		return nil, errors.New("mock test service name watch err")
 	}
 	return &mockWatch{ctx: ctx, isSecure: d.isSecure, nextErr: d.nextErr, stopErr: d.stopErr}, nil
 }
@@ -116,7 +116,7 @@ func (m *mockWatch) Next() ([]*registry.ServiceInstance, error) {
 
 func (m *mockWatch) Stop() error {
 	if m.stopErr {
-		return fmt.Errorf("mock test error")
+		return errors.New("mock test error")
 	}
 	// 标记 next 需要报错
 	m.nextErr = true
diff --git a/transport/http/server_test.go b/transport/http/server_test.go
index 05bc8399..ff9b3918 100644
--- a/transport/http/server_test.go
+++ b/transport/http/server_test.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"crypto/tls"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"io"
 	"net"
@@ -13,8 +14,7 @@ import (
 	"testing"
 	"time"
 
-	"github.com/go-kratos/kratos/v2/errors"
-
+	kratoserrors "github.com/go-kratos/kratos/v2/errors"
 	"github.com/go-kratos/kratos/v2/internal/host"
 )
 
@@ -49,9 +49,9 @@ func TestServeHTTP(t *testing.T) {
 	mux := NewServer(Listener(ln))
 	mux.HandleFunc("/index", h)
 	mux.Route("/errors").GET("/cause", func(ctx Context) error {
-		return errors.BadRequest("xxx", "zzz").
+		return kratoserrors.BadRequest("xxx", "zzz").
 			WithMetadata(map[string]string{"foo": "bar"}).
-			WithCause(fmt.Errorf("error cause"))
+			WithCause(errors.New("error cause"))
 	})
 	if err = mux.WalkRoute(func(r RouteInfo) error {
 		t.Logf("WalkRoute: %+v", r)
@@ -65,7 +65,7 @@ func TestServeHTTP(t *testing.T) {
 	srv := http.Server{Handler: mux}
 	go func() {
 		if err := srv.Serve(ln); err != nil {
-			if errors.Is(err, http.ErrServerClosed) {
+			if kratoserrors.Is(err, http.ErrServerClosed) {
 				return
 			}
 			panic(err)
@@ -87,9 +87,9 @@ func TestServer(t *testing.T) {
 		_ = json.NewEncoder(w).Encode(testData{Path: r.RequestURI})
 	})
 	srv.Route("/errors").GET("/cause", func(ctx Context) error {
-		return errors.BadRequest("xxx", "zzz").
+		return kratoserrors.BadRequest("xxx", "zzz").
 			WithMetadata(map[string]string{"foo": "bar"}).
-			WithCause(fmt.Errorf("error cause"))
+			WithCause(errors.New("error cause"))
 	})
 
 	if e, err := srv.Endpoint(); err != nil || e == nil || strings.HasSuffix(e.Host, ":0") {
@@ -135,7 +135,7 @@ func testAccept(t *testing.T, srv *Server) {
 		}
 		req.Header.Set("Content-Type", test.contentType)
 		resp, err := client.Do(req)
-		if errors.Code(err) != 400 {
+		if kratoserrors.Code(err) != 400 {
 			t.Errorf("expected 400 got %v", err)
 		}
 		if err == nil {
@@ -205,7 +205,7 @@ func testClient(t *testing.T, srv *Server) {
 			t.Fatal(err)
 		}
 		resp, err := client.Do(req)
-		if errors.Code(err) != test.code {
+		if kratoserrors.Code(err) != test.code {
 			t.Fatalf("want %v, but got %v", test, err)
 		}
 		if err != nil {
@@ -231,7 +231,7 @@ func testClient(t *testing.T, srv *Server) {
 	for _, test := range tests {
 		var res testData
 		err := client.Invoke(context.Background(), test.method, test.path, nil, &res)
-		if errors.Code(err) != test.code {
+		if kratoserrors.Code(err) != test.code {
 			t.Fatalf("want %v, but got %v", test, err)
 		}
 		if err != nil {
@@ -316,8 +316,8 @@ func TestRequestDecoder(t *testing.T) {
 	o := &Server{}
 	v := func(*http.Request, interface{}) error { return nil }
 	RequestDecoder(v)(o)
-	if o.dec == nil {
-		t.Errorf("expected nil got %v", o.dec)
+	if o.decBody == nil {
+		t.Errorf("expected nil got %v", o.decBody)
 	}
 }