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中间件的资料请关注代码网其它相关文章!
发表评论