一、中间件的概念
在go语言中,中间件是一种用于处理http请求的开发模式,允许开发人员在请求到达处理程序之前或之后执行特定的操作,如日志记录、身份验证、错误处理等。
中间件通常是一个函数,它接收一个 `http.handler` 作为参数并返回另一个 `http.handler`。
go源码中 handler 的定义如下:
type handler interface { servehttp(responsewriter, *request) }
二、go原生http中使用中间件的方法
使用方法:
1、创建中间件函数,输入参数 http.handler,输出参数 http.handler
2、将处理器函数作为参数传入上述中间件函数
3、运用 handle(pattern string, handler handler) 等函数将中间件函数绑定到请求路由中
代码示例:
package main import ( "fmt" "log" "net/http" ) // 日志记录中间件 func loggingmiddleware(next http.handler) http.handler { return http.handlerfunc(func(w http.responsewriter, r *http.request) { log.printf("请求处理之前 request uri: %s\n", r.requesturi) next.servehttp(w, r) log.printf("处理程序之后进行的操作...\n") }) } // handler 处理函数 func sayhello(w http.responsewriter, r *http.request) { fmt.println("hello world") } func main() { //创建一个 http 请求路由器 mux := http.newservemux() // 使用日志记录中间件 mux.handle("/index", loggingmiddleware(http.handlerfunc(sayhello))) //启动服务,使用创建的 servemux http.listenandserve(":8081", mux) }
运行效果:
三、go微服务框架kratos使用中间件的方法
kratos介绍中间件的d88尊龙官网手机app官网地址:
1、内置中间件使用方法
①通过 middleware(m ...middleware.middleware) serveroption 添加所需的中间件
②将上述由中间件组成的 serveroption 添加到 []http.serveroption 中
③通过函数 newserver(opts ...serveroption) *server 创建 httpserver
代码示例:
func newhttpserver(c *conf.server, logger log.logger, blog *service.blogservice) *http.server { opts := []http.serveroption{ http.middleware( //使用kratos内置中间件 recovery.recovery(), tracing.server(), logging.server(logger), validate.validator(), ), } if c.http.network != "" { opts = append(opts, http.network(c.http.network)) } if c.http.addr != "" { opts = append(opts, http.address(c.http.addr)) } if c.http.timeout != nil { opts = append(opts, http.timeout(c.http.timeout.asduration())) } //创建 httpserver srv := http.newserver(opts...) v1.registerblogservicehttpserver(srv, blog) return srv }
2、自定义中间件使用方法
①实现 middleware.middleware 接口,其定义如下:
// handler defines the handler invoked by middleware. type handler func(ctx context.context, req interface{}) (interface{}, error) // middleware is http/grpc transport middleware. type middleware func(handler) handler
中间件中您可以使用 tr, ok := transport.fromservercontext(ctx)
获得 transporter 实例以便访问接口相关的元信息。
②像添加内置中间件一样,将自定义中间件添加到 http.middleware 和 []http.serveroption 中
③通过函数 newserver(opts ...serveroption) *server 创建 httpserver
代码示例:
// auth.go 单元 //自定义 jwt 认证中间件 func jwtauth(jwtsecret string) 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 { tokenstring := tr.requestheader().get("authorization") spew.dump(tokenstring) //token, err := jwt.parsewithclaims(tokenstring, &jwt.standardclaims{}, func(token *jwt.token) (interface{}, error) { token, err := jwt.parse(tokenstring, func(token *jwt.token) (interface{}, error) { // don't forget to validate the alg is what you expect: if _, ok := token.method.(*jwt.signingmethodhmac); !ok { return nil, fmt.errorf("unexpected signing method: %v", token.header["alg"]) } // hmacsamplesecret is a []byte containing your secret, e.g. []byte("my_secret_key") return []byte(jwtsecret), nil }) if err != nil { log.fatal(err) } if claims, ok := token.claims.(jwt.mapclaims); ok { fmt.println(claims["iss"], claims["exp"]) //fmt.println(claims.issuer, claims.expiresat) } else { fmt.println(err) } } return handler(ctx, req) } } } // server/http.go 单元 func newhttpserver(c *conf.server, confauth *conf.auth, logger log.logger, blog *service.blogservice) *http.server { opts := []http.serveroption{ http.middleware( //自定义中间件 jwtauth auth.jwtauth(confauth.jwtsecrect), ), } if c.http.network != "" { opts = append(opts, http.network(c.http.network)) } if c.http.addr != "" { opts = append(opts, http.address(c.http.addr)) } if c.http.timeout != nil { opts = append(opts, http.timeout(c.http.timeout.asduration())) } //创建 httpserver srv := http.newserver(opts...) v1.registerblogservicehttpserver(srv, blog) return srv }
3、为特定路由定制中间件的使用方法
使用方法:
对特定路由定制中间件:
server: selector.server(ms...)
client: selector.client(ms...)
代码示例:
// server/http.go 单元 // 添加验证白名单 func newwhitelistmatcher() selector.matchfunc { whitelist := make(map[string]struct{}) whitelist["/blog.api.v1.account/login"] = struct{}{} whitelist["/blog.api.v1.account/register"] = struct{}{} return func(ctx context.context, operation string) bool { if _, ok := whitelist[operation]; ok { return false } return true } } // server/http.go 单元 func newhttpserver(c *conf.server, confauth *conf.auth, logger log.logger, blog *service.blogservice) *http.server { opts := []http.serveroption{ http.middleware( //自定义中间件 jwtauth selector.server(auth.jwtauth(confauth.jwtsecrect)). match(newwhitelistmatcher()). build(), ), } if c.http.network != "" { opts = append(opts, http.network(c.http.network)) } if c.http.addr != "" { opts = append(opts, http.address(c.http.addr)) } if c.http.timeout != nil { opts = append(opts, http.timeout(c.http.timeout.asduration())) } //创建 httpserver srv := http.newserver(opts...) v1.registerblogservicehttpserver(srv, blog) return srv }
注意: 定制中间件是通过 operation 匹配,并不是 http 本身的路由!!!
grpc path 的拼接规则为 /包名.服务名/方法名(/package.service/method)
。