golang原生http实现中间件
中间件(middleware):常被用来做认证校验、审计等
大家常用的iris、gin等web框架,都包含了中间件逻辑。但有时我们引入该框架显得较为繁重,本文将介绍通过golang原生http来实现中间件操作。全部代码:https://github.com/ziyifast/ziyifast-code_instruction/tree/main/middleware
1 定义http.handler:具体中间件操作
①corsmiddleware:允许跨域
// corsmiddleware handles cross-origin resource sharing (cors) responses. func corsmiddleware(next http.handler) http.handler { fmt.println("cors middleware....") return http.handlerfunc(func(w http.responsewriter, r *http.request) { if r.method == "options" { w.header().set("access-control-allow-origin", "*") w.header().set("access-control-allow-methods", "get, post, options, delete") //如果前后端需要传递自定义请求头,需要再access-control-allow-headers中匹配(yi-auth-token) w.header().set("access-control-allow-headers", "content-type, accept, yi-auth-token") w.writeheader(http.statusok) return } w.header().set("access-control-allow-origin", "*") w.header().set("access-control-allow-methods", "get, post, options, delete") w.header().set("access-control-allow-headers", "content-type,accept,yi-auth-token") //交给下一个中间件处理 next.servehttp(w, r) }) }
②authmiddleware:认证
// authmiddleware simulates a simple authentication middleware. func authmiddleware(next http.handler) http.handler { return http.handlerfunc(func(w http.responsewriter, r *http.request) { fmt.println("auth middleware...") //store info in ctx token := r.header.get("token") if len(token) != 0 { //todo 1. check token 2. get userinfo from token userid := "1" ctx := context.withvalue(r.context(), "userid", userid) r = r.withcontext(ctx) } next.servehttp(w, r) }) }
③auditmiddleware:审计操作
// auditmiddleware simulates an audit logging middleware. func auditmiddleware(next http.handler) http.handler { return http.handlerfunc(func(w http.responsewriter, r *http.request) { fmt.println("audit middleware...") next.servehttp(w, r) }) }
④smokehandler:具体处理操作
// smokehandler returns the current time as a string. func smokehandler(w http.responsewriter, r *http.request) { fmt.println("smoke handle....") _, err := w.write([]byte(time.now().string())) if err != nil { http.error(w, "internal server error", http.statusinternalservererror) } }
2 义中间件类型&定义中间件链
①type middleware func(http.handler) http.handler:定义中间件
type middleware func(http.handler) http.handler
②定义中间件链middlewarechain
// newmiddlewarechain creates a new middleware chain with the given middlewares. func newmiddlewarechain(middlewares ...middleware) middleware { return func(handler http.handler) http.handler { for i := len(middlewares) - 1; i >= 0; i-- { handler = middlewares[i](handler) } return handler } }
3 启动http服务
func runandserve() error { defer func() { if e := recover(); e != nil { fmt.println("err=", e) } }() mux := http.newservemux() // create middleware chains for routes. authmiddlewarechain := newmiddlewarechain(corsmiddleware, authmiddleware, auditmiddleware) //noauthmiddlewarechain := newmiddlewarechain(corsmiddleware) // convert the middleware chain result to http.handlerfunc. smokehandlerwrapped := func(w http.responsewriter, r *http.request) { authmiddlewarechain(http.handlerfunc(smokehandler)).servehttp(w, r) } mux.handlefunc("/smoke", smokehandlerwrapped) fmt.printf("listening on http://localhost:%d\n", 9999) return http.listenandserve(":9999", mux) }
4 测试
启动后端
go run main.go
2. 浏览器访问http://localhost:9999/smoke
3. 后端日志打印
可以看到是最后才处理我们的业务handler
全部代码
package main import ( "context" "fmt" "net/http" "time" ) type middleware func(http.handler) http.handler // corsmiddleware handles cross-origin resource sharing (cors) responses. func corsmiddleware(next http.handler) http.handler { fmt.println("cors middleware....") return http.handlerfunc(func(w http.responsewriter, r *http.request) { if r.method == "options" { w.header().set("access-control-allow-origin", "*") w.header().set("access-control-allow-methods", "get, post, options, delete") //如果前后端需要传递自定义请求头,需要再access-control-allow-headers中匹配(yi-auth-token) w.header().set("access-control-allow-headers", "content-type, accept, yi-auth-token") w.writeheader(http.statusok) return } w.header().set("access-control-allow-origin", "*") w.header().set("access-control-allow-methods", "get, post, options, delete") w.header().set("access-control-allow-headers", "content-type,accept,yi-auth-token") next.servehttp(w, r) }) } // authmiddleware simulates a simple authentication middleware. func authmiddleware(next http.handler) http.handler { return http.handlerfunc(func(w http.responsewriter, r *http.request) { fmt.println("auth middleware...") //store info in ctx token := r.header.get("token") if len(token) != 0 { //todo 1. check token 2. get userinfo from token userid := "1" ctx := context.withvalue(r.context(), "userid", userid) r = r.withcontext(ctx) } next.servehttp(w, r) }) } // auditmiddleware simulates an audit logging middleware. func auditmiddleware(next http.handler) http.handler { return http.handlerfunc(func(w http.responsewriter, r *http.request) { fmt.println("audit middleware...") next.servehttp(w, r) }) } // smokehandler returns the current time as a string. func smokehandler(w http.responsewriter, r *http.request) { fmt.println("smoke handle....") _, err := w.write([]byte(time.now().string())) if err != nil { http.error(w, "internal server error", http.statusinternalservererror) } } // newmiddlewarechain creates a new middleware chain with the given middlewares. func newmiddlewarechain(middlewares ...middleware) middleware { return func(handler http.handler) http.handler { for i := len(middlewares) - 1; i >= 0; i-- { handler = middlewares[i](handler) } return handler } } func runandserve() error { defer func() { if e := recover(); e != nil { fmt.println("err=", e) } }() mux := http.newservemux() // create middleware chains for routes. authmiddlewarechain := newmiddlewarechain(corsmiddleware, authmiddleware, auditmiddleware) //noauthmiddlewarechain := newmiddlewarechain(corsmiddleware) // convert the middleware chain result to http.handlerfunc. smokehandlerwrapped := func(w http.responsewriter, r *http.request) { authmiddlewarechain(http.handlerfunc(smokehandler)).servehttp(w, r) } mux.handlefunc("/smoke", smokehandlerwrapped) fmt.printf("listening on http://localhost:%d\n", 9999) return http.listenandserve(":9999", mux) } func main() { runandserve() }
以上就是golang使用原生http实现中间件的代码详解的详细内容,更多关于golang http中间件的资料请关注代码网其它相关文章!
发表评论