跳到主要内容

路由定义

func Router(engine *httpserver.Engine) {
// 静态路由
core.Get("/foo", Index)
core.Post("/bar", Index)
core.Put("/put-foo", Index)
core.Delete("/delete-bar", Index)

// 路由分组
prefix := core.Prefix("/group")
prefix.Get("/foo", Index) // http://localhsot:8080/group/foo
prefix.Get("/bar", Index) // http://localhsot:8080/group/bar

}

// 上面所有示例路由都绑定的这个函数
func Index(ctx *httpserver.Context) {
ctx.Resp.Text("Test")
}

使用中间件

单个路由挂中间件

我们可以在定义路由时通过可变参数为路由添加中间件,例如我们加一个请求超时的中间件

func Router(engine *httpserver.Engine) {
core.Get("/foo", Index, middleware.Timeout(5))

// 可以同时添加多个中间件,会依次按顺序执行
core.Get("/foo", Index, middleware.Timeout(5), middleware.Logger())
}

分组路由挂中间件

为分组绑定中间件会对分组下所有路由生效

func Router(engine *httpserver.Engine) {
prefix := engine.Prefix("/group").UseMiddleware(middleware.Timeout(5))
{
prefix.Get("/foo", Index)
prefix.Get("/bar", Index)
}
}

分组内的路由可以再单独使用中间件

func Router(engine *httpserver.Engine) {
prefix := core.Prefix("/group").UseMiddleware(middleware.Timeout(5))
{
prefix.Get("/foo", Index, middleware.Timeout(10))
}
}

全局中间件

全局中间件对所有路由生效,可以挂多个中间件,会依次执行。

func Router(engine *httpserver.Engine) {

// 全局中间件
engine.UseMiddleware(
middleware.Timeout(2*time.Second),
middleware.Recovery(map[string]interface{}{
"msg": "Server Error",
}),
)

prefix.Get("/foo", Index, middleware.Timeout(10))
}
注意

1、同一个中间件如果同时绑定在全局、分组、单个路由上,则按优先级进行覆盖,优先级高的覆盖优先级低的。优先级为:单个路由绑定中间件 > 分组绑定中间件 > 全局绑定中间件 2、全局中间的代码写在路由定义前面或者后面都可以,不会影响执行顺序。

内置中间件

Goodle 内置了一些中间,您可以选择使用。

超时处理

prefix.Get("/foo", Index, middleware.Timeout(10))

每个 http 请求都分配了一个协程去处理任务,上面设置了 5 秒超时,则这个路由上的请求如果 5 秒还没处理完则会结束协程。

错误恢复

当出现异常时从 Recovery 中恢复并返回自定义的错误消息,这个中间件一般挂在全局上面对所有路由生效。

func Router(engine *httpserver.Engine) {
engine.UseMiddleware(
middleware.Recovery(map[string]interface{}{
"msg": "Server Error",
}),
)
}
提示

Recover 中间件在发生错误时会把调用栈给屏蔽掉,换成自定义错误消息,这对开发时不友好。所以当 app.yaml 中设置 debug: true 时 Recover 中间件不工作。

Token 鉴权

首先在 app.ymal 中配置一个 token 密钥

tokenSecret: abcdefg

然后在路由上挂中间件,例如挂在一个路由分组上

package routing

import (
"chord/internal/api"
"cvgo/provider/httpserver"
"cvgo/provider/httpserver/middleware"
)

// 路由定义
func Routes(engine *httpserver.Engine) {
// 公开 api
engine.Get("/", api.Index)

// 需要验证 token 的 api 分组
authGroup := engine.Prefix("/api").UseMiddleware(middleware.Auth())
{
authGroup.Get("/demo", api.Index)
}

}

最后,在注册登录的时候使用脚手架 cvgo/kit/cryptokit 包提供的以下方法将用户 id 加密进去

uid := 1
cryptokit.DynamicEncrypt(app.Config.GetTokenSecret(), uid)
提示

cryptokit 包提供的一对字符串加解密方法 DynamicEncrypt() 和 DynamicDecrypt() 方法是一对可逆的加解密算法。 同样的明文加密出来的密文每次都不一样,是动态变的,还支持 token 失效时间设置。

如果你需要在 token 中加密更多信息,可以基于 cvgo/provider/httpserver/middleware/auth.go 自行修改为自定义中间件。

使用 cvg create-module <moduleName> --webserver=cvg 创建的模块,默认已经加上了鉴权中间件,在模块 app.yaml 中生成了一个 16 位长度的随机字符串作为 secret

i18n

Cvgo 的 i18n 用起来非常简单,只需要启用 i18n 中间件,然后创建你的语言包文件即可。详细步骤查看 i18n 国际化 章节

自定义中间件

1、在你的项目中创建中间件,可以将其放置到你项目任意位置

auth.go
package middleware

import (
"errors"
"cvgo/provider/httpserver"
)

func MyMiddleware() httpserver.MiddlewareHandler {
return func(context *httpserver.Context) error {
if 1+1 == 2 {
fmt.Println("1+1 确实等于 2")
context.SetVal("result", 1+1)
context.Next()
return nil
}
return errors.New("1+1 不等于 2,请求结束。")
}
}

2、在路由上挂这个中间件

func Router(core *httpserver.Engine) {
core.UseMiddleware(middleware.MyMiddleware())
}

3、前面中间件我们通过 context.SetVal("result", 2)1+1 的结果存在了 context 里面,然后我们可以在路由的响应函数中取出来:

func Userinfo(ctx *httpserver.Context) {
result := ctx.GetVal("result").ToInt()
clog.GreenPrintln(result)
}

跨域支持

在路由定义前调用 engine.Cross()

func Routes(engine *httpserver.Engine) {
engine.Cross()
}