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 middlewareimport (    "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() 跨域设置
// exampleserver := 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() 自定义跨域办法
// examplevar 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
// examplerest.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 能够同时应用
// examplerest.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 原理不简单,有趣味的能够翻阅源码学习