go-zero 作为一个微服务框架,不仅给咱们提供了很好的参考,而且外围代码量不多,咱们能够在空闲工夫读读他的外围代码,来多多学习充电。
rest 局部
代码构造
rest
├── handler // 自带中间件
│ ├── authhandler.go // 权限
│ ├── breakerhandler.go // 断路器
│ ├── contentsecurityhandler.go // 平安验证
│ ├── cryptionhandler.go // 加密解密
│ ├── gunziphandler.go // zip 压缩
│ ├── loghandler.go // 日志
│ ├── maxbyteshandler.go // 最大申请数据限度
│ ├── maxconnshandler.go // 最大申请连接数限度
│ ├── metrichandler.go // 申请指标统计
│ ├── prometheushandler.go // prometheus 上报
│ ├── recoverhandler.go // 谬误捕捉
│ ├── sheddinghandler.go // 过载爱护
│ ├── timeouthandler.go // 超时管制
│ └── tracinghandler.go // 链路追踪
├── httpx
│ ├── requests.go
│ ├── responses.go
│ ├── router.go
│ ├── util.go
│ └── vars.go
├── internal
│ ├── cors // 跨域解决
│ │ └── handlers.go
│ ├── response
│ │ ├── headeronceresponsewriter.go
│ │ └── withcoderesponsewriter.go
│ ├── security // 加密解决
│ │ └── contentsecurity.go
│ ├── log.go
│ └── starter.go
├── pathvar // path 参数解析
│ └── params.go
├── router
│ └── patrouter.go
├── token
│ └── tokenparser.go
├── config.go // 配置
├── engine.go // 引擎
├── server.go
└── types.go
服务启动流程
咱们以 go-zero-example 我的项目 http/demo/main.go 代码来剖析
go-zero 给咱们提供了如下组件与服务,咱们来逐个浏览剖析
- http 框架惯例组件(路由、调度器、中间件、跨域)
- 权限管制
- 断路器
- 限流器
- 过载爱护
- prometheus
- trace
- cache
http 框架惯例组件
路由
路由应用的是二叉查找树,高效的路由都会应用树形构造来构建
二叉查找树可参见源码
https://github.com/zeromicro/…
go-zero 路由实现了 http\server.go Handler interface 来拦挡每个申请
入口源码地址: github.com/zeromicro/go-zero/rest/router/patrouter.go
func (pr *patRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {reqPath := path.Clean(r.URL.Path) // 返回相当于 path 的最短门路名称
if tree, ok := pr.trees[r.Method]; ok { // 查找对应 http method
if result, ok := tree.Search(reqPath); ok { // 查找路由 path
if len(result.Params) > 0 {r = pathvar.WithVars(r, result.Params) // 获取路由参数并且增加到 *http.Request 中
}
result.Item.(http.Handler).ServeHTTP(w, r) // 调度办法
return
}
}
allows, ok := pr.methodsAllowed(r.Method, reqPath)
if !ok {pr.handleNotFound(w, r)
return
}
if pr.notAllowed != nil {pr.notAllowed.ServeHTTP(w, r)
} else {w.Header().Set(allowHeader, allows)
w.WriteHeader(http.StatusMethodNotAllowed)
}
}
调度器
go-zero 没有调度器,在上文 ServeHTTP 中曾经应用了调度器,这归纳于 golang 曾经给咱们实现了一个很好的 http 模块,如果是其余语言,咱们在设计框架的时候往往要本人实现调度器。
中间件
咱们能够在 *.api 中增加如下代码来应用
@server(middleware: Example // 路由中间件申明)
service User {
@handler UserInfo
post /api/user/userinfo returns (UserInfoResponse)
}
通过生成代码命令,生成的代码如下
package middleware
import (
"log"
"net/http"
)
type ExampleMiddleware struct{}
func NewExampleMiddleware() *ExampleMiddleware {return &ExampleMiddleware{}
}
func (m *ExampleMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {return func(w http.ResponseWriter, r *http.Request) {
// TODO generate middleware implement function, delete after code implementation
next(w, r)
}
}
go-zero 给咱们提供了一些罕用的中间件,不便咱们在开发时候应用
- rest.WithCors() 跨域设置
// example
server := rest.MustNewServer(c.RestConf, rest.WithCors("localhost:8080"))
// 源码
func WithCors(origin ...string) RunOption {return func(server *Server) {server.router.SetNotAllowedHandler(cors.NotAllowedHandler(nil, origin...))
server.Use(cors.Middleware(nil, origin...))
}
}
跨域
- resrt.WithCustomCors() 自定义跨域办法
// example
var origins = []string{"localhost:8080",}
server := rest.MustNewServer(c.RestConf,
rest.WithCustomCors(
// 设置 http header
func(header http.Header) {header.Set("Access-Control-Allow-Origin", "Access-Control-Allow-Origin")
},
// 不容许地址返回指定数据
func(writer http.ResponseWriter) {writer.Write([]byte("not allow"))
},
// 容许跨域地址
origins...,
),
)
// 源码
func WithCustomCors(middlewareFn func(header http.Header), notAllowedFn func(http.ResponseWriter),
origin ...string) RunOption {return func(server *Server) {server.router.SetNotAllowedHandler(cors.NotAllowedHandler(notAllowedFn, origin...))
server.Use(cors.Middleware(middlewareFn, origin...))
}
}
- rest.WithJwt() jwt
// example
rest.WithJwt("uOvKLmVfztaXGpNYd4Z0I1SiT7MweJhl")
// 源码
func WithJwt(secret string) RouteOption {return func(r *featuredRoutes) {validateSecret(secret)
r.jwt.enabled = true
r.jwt.secret = secret
}
}
- rest.WithJwtTransition() jwt token 转换,新老 token 能够同时应用
// example
rest.WithJwtTransition("uOvKLmVfztaXGpNYd4Z0I1SiT7MweJhl", "uOvKLmVfztaXGpNYd4Z0I1SiT7MweJh2")
// 源码
func WithJwtTransition(secret, prevSecret string) RouteOption {return func(r *featuredRoutes) {
// why not validate prevSecret, because prevSecret is an already used one,
// even it not meet our requirement, we still need to allow the transition.
validateSecret(secret)
r.jwt.enabled = true
r.jwt.secret = secret
r.jwt.prevSecret = prevSecret
}
}
权限管制
入口源码地址:github.com/zeromicro/go-zero/rest/handler/authhandler.go
权限管制外围文件带正文代码如下,大家能够参阅
- https://github.com/TTSimple/g…
- https://github.com/TTSimple/g…
go-zero 提供 jwt 权限管制,jwt 只做登录与未登录验证,细粒度的权限验证咱们能够应用其余成熟计划
jwt 原理不简单,有趣味的能够翻阅源码学习