朱纯树博客
VPS测评推荐网站
cloudacead cloudacead

golang框架GoFrame重要知识点整理

golang 框架 goFrame 重要知识点整理

本文介绍 golang 框架 GoFrame 的重要知识点。本文不会前面介绍 goframe,仅罗列重要的点。

1. 路由注册

GoFrame 支持各种各样的路由注册方式,非常灵活。
但实际上只需要掌握官方推荐的一种注册方式即可: 以嵌套的方式定义分组路由。
这种方式的推荐理由:

  • 以分组方式,方便管理路由
  • 以嵌套方式,方便从代码角度一眼看出路由的上下级层次。
    示例如下:
package main

import (
    "net/http"

    "github.com/gogf/gf/frame/g"
    "github.com/gogf/gf/net/ghttp"
)

func MiddlewareAuth(r *ghttp.Request) {
    token := r.Get("token")
    if token == "123456" {
        r.Middleware.Next()
    } else {
        r.Response.WriteStatus(http.StatusForbidden)
    }
}

func MiddlewareCORS(r *ghttp.Request) {
    r.Response.CORSDefault()
    r.Middleware.Next()
}

func MiddlewareLog(r *ghttp.Request) {
    r.Middleware.Next()
    g.Log().Println(r.Response.Status, r.URL.Path)
}

func main() {
    s := g.Server()
    s.Use(MiddlewareLog)
    s.Group("/api.v2", func(group *ghttp.RouterGroup) {
        group.Middleware(MiddlewareAuth, MiddlewareCORS)
        group.GET("/test", func(r *ghttp.Request) {
            r.Response.Write("test")
        })
        group.Group("/order", func(group *ghttp.RouterGroup) {
            group.GET("/list", func(r *ghttp.Request) {
                r.Response.Write("list")
            })
            group.PUT("/update", func(r *ghttp.Request) {
                r.Response.Write("update")
            })
        })
        group.Group("/user", func(group *ghttp.RouterGroup) {
            group.GET("/info", func(r *ghttp.Request) {
                r.Response.Write("info")
            })
            group.POST("/edit", func(r *ghttp.Request) {
                r.Response.Write("edit")
            })
            group.DELETE("/drop", func(r *ghttp.Request) {
                r.Response.Write("drop")
            })
        })
        group.Group("/hook", func(group *ghttp.RouterGroup) {
            group.Hook("/*", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
                r.Response.Write("hook any")
            })
            group.Hook("/:name", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
                r.Response.Write("hook name")
            })
        })
    })
    s.SetPort(8199)
    s.Run()
}

2. 请求输入

2.1 按参数类型获取参数

Get*Struct 和 GetBody/GetBodyString 的区别
接口参数中有一种特殊的参数: 自定义参数,往往在服务端的中间件、服务函数中通过 SetParam/GetParam 方法管理

Get*(或 GetRequset*)方法存在优先级:Router Body

2.2 参数绑定到对象(推荐)

若想将接口参数(支持所有类型的参数: query、form、json 等)绑定到 struct 上,框架默认支持,无需指定 tag。
若想自定义绑定规则,则可使用 tag 标签自定义。

package main

import (
    "github.com/gogf/gf/frame/g"
    "github.com/gogf/gf/net/ghttp"
)

type RegisterReq struct {
    Name  string
    Pass  string `p:"password1"`
    Pass2 string `p:"password2"`
}

type RegisterRes struct {
    Code  int         `json:"code"`
    Error string      `json:"error"`
    Data  interface{} `json:"data"`
}

func main() {
    s := g.Server()
    s.BindHandler("/register", func(r *ghttp.Request) {
        var req *RegisterReq
        if err := r.Parse(&req); err != nil {
            r.Response.WriteJsonExit(RegisterRes{
                Code:  1,
                Error: err.Error(),
            })
        }
        // ...
        r.Response.WriteJsonExit(RegisterRes{
            Data: req,
        })
    })
    s.SetPort(8199)
    s.Run()
}

2.3 请求校验

推荐的错误校验方法: 当产生错误时,我们可以将校验错误转换为*gvalid.Error对象,随后可以通过灵活的方法控制错误的返回。

package main

import (
    "github.com/gogf/gf/frame/g"
    "github.com/gogf/gf/net/ghttp"
    "github.com/gogf/gf/util/gvalid"
)

type RegisterReq struct {
    Name  string `p:"username"  v:"required|length:6,30#请输入账号|账号长度为:min到:max位"`
    Pass  string `p:"password1" v:"required|length:6,30#请输入密码|密码长度不够"`
    Pass2 string `p:"password2" v:"required|length:6,30|same:password1#请确认密码|密码长度不够|两次密码不一致"`
}

type RegisterRes struct {
    Code  int         `json:"code"`
    Error string      `json:"error"`
    Data  interface{} `json:"data"`
}

func main() {
    s := g.Server()
    s.BindHandler("/register", func(r *ghttp.Request) {
        var req *RegisterReq
        if err := r.Parse(&req); err != nil {
            // Validation error.
            if v, ok := err.(*gvalid.Error); ok {
                r.Response.WriteJsonExit(RegisterRes{
                    Code:  1,
                    Error: v.FirstString(),
                })
            }
            // Other error.
            r.Response.WriteJsonExit(RegisterRes{
                Code:  1,
                Error: err.Error(),
            })
        }
        // ...
        r.Response.WriteJsonExit(RegisterRes{
            Data: req,
        })
    })
    s.SetPort(8199)
    s.Run()
}

测试结果:

$ curl "http://127.0.0.1:8199/register"
{"code":1,"error":"请输入账号","data":null}

$ curl "http://127.0.0.1:8199/register?name=john&password1=123456&password2=12345"
{"code":1,"error":"两次密码不一致","data":null}

2.4 自定义变量

开发者可以在请求中自定义一些变量设置,自定义变量的获取优先级是最高的,可以覆盖原有的客户端提交参数。

自定义变量可以通过 SetParam 方法进行设置。自定义变量的获取可以通过请求参数的获取方法获得到,例如:Get/GetVar/GetMap 等等,也可以通过特定的自定义变量方法获取到 GetParam/GetParamVar

package main

import (
    "github.com/gogf/gf/frame/g"
    "github.com/gogf/gf/net/ghttp"
)

// 前置中间件1
func MiddlewareBefore1(r *ghttp.Request) {
    r.SetParam("name", "GoFrame")
    r.Response.Writeln("set name")
    r.Middleware.Next()
}

// 前置中间件2
func MiddlewareBefore2(r *ghttp.Request) {
    r.SetParam("site", "https://goframe.org")
    r.Response.Writeln("set site")
    r.Middleware.Next()
}

func main() {
    s := g.Server()
    s.Group("/", func(group *ghttp.RouterGroup) {
        group.Middleware(MiddlewareBefore1, MiddlewareBefore2)
        group.ALL("/", func(r *ghttp.Request) {
            r.Response.Writefln(
                "%s: %s",
                r.GetParamVar("name").String(),
                r.GetParamVar("site").String(),
            )
        })
    })
    s.SetPort(8199)
    s.Run()
}

结果:

set name
set site
GoFrame: https://goframe.org

2.5 上下文变量

上下文变量自定义变量的区别:自定义变量会覆盖接口参数,而上下文变量不会覆盖。

3. 请求输出

3.1 缓冲区

Response 输出采用了缓冲控制,输出的内容预先写入到一块缓冲区,等待服务方法执行完毕后才真正地输出到客户端。该特性在提高执行效率同时为输出内容的控制提供了更高的灵活性。

可应用于全局异常处理场景: 接口出现异常, 重新定义接口的输出内容。

package main

import (
    "github.com/gogf/gf/frame/g"
    "github.com/gogf/gf/net/ghttp"
    "net/http"
)

func MiddlewareErrorHandler(r *ghttp.Request) {
    r.Middleware.Next()
    if r.Response.Status >= http.StatusInternalServerError {
        r.Response.ClearBuffer()
        r.Response.Writeln("服务器居然开小差了,请稍后再试吧!")
    }
}

func main() {
    s := g.Server()
    s.Group("/api.v2", func(group *ghttp.RouterGroup) {
        group.Middleware(MiddlewareErrorHandler)
        group.ALL("/user/list", func(r *ghttp.Request) {
            panic("db error: sql is xxxxxxx")
        })
    })
    s.SetPort(8199)
    s.Run()
}

4. session

GF 框架的 Session 默认过期时间是 24 小时

SessionId 默认通过 Cookie 来传递,并且也支持客户端通过 Header 传递 SessionId,SessionId 的识别名称可以通过 ghttp.Server 的 SetSessionIdName 进行修改。
ghttp.Server 中的 SessionId 使用的是客户端的 RemoteAddr + Header 请求信息通过 guid 模块来生成的,保证随机及唯一性

自定义 session 的过期时间:

    s := g.Server()
    s.SetConfigWithMap(g.Map{
        "SessionMaxAge": time.Minute,
    })

gsession 实现并为开发者提供了常见的三种 Session 存储实现方式:

  • 基于文件存储(默认)
    单节点部署方式下比较高效的持久化存储方式;
    重启程序后,session 数据不丢失,自动加载到内存。
  • 基于纯内存存储
    性能最高效,但是无法持久化保存,重启即丢失;
    s := g.Server()
    s.SetConfigWithMap(g.Map{
        "SessionMaxAge":  time.Minute,
        "SessionStorage": gsession.NewStorageMemory(),
    })
  • 基于 Redis 存储
    适用于多节点部署的场景;

5. 配置管理

2 种配置方式: 代码或配置文件
服务启动后不允许修改配置
用户提交的数据大小限制的配置项:

[server]
    MaxHeaderBytes    = "20KB"
    ClientMaxBodySize = "200MB"

6. 全局异常处理

默认情况下,全局异常会记录到日志中。
开发者也可以自定义异常处理逻辑。异常信息的获取: Request 对象中的 GetError 方法

疑问:即使开发者有自己捕获记录异常错误的日志,但是Server依旧会打印到Server自己的错误日志文件中中的 server 自己的错误日志文件指的是?

7. HTTP 客户端

推荐使用单例对象g.Client()
基于连接池。
支持链式操作
若默认的单例客户端不满足需求,可以自定义客户端。

*Bytes*Content 方法:
以 Bytes 及 Content 后缀结尾的请求方法为直接获取返回内容的快捷方法,这些方法将会自动读取服务端返回内容并自动关闭请求连接。需要注意的是,如果请求执行失败,返回内容将会为空。

*Bytes*Content 方法:
必须手动调用 Close 方法关闭

*Var 方法:
若服务端返回 json 或 xml 数据时, 可使用该方法转换为对象

文章来源于互联网:
golang框架GoFrame重要知识点整理

赞(0) 打赏
未经允许不得转载:VPS测评推荐网站 - 朱纯树博客 » golang框架GoFrame重要知识点整理

评论 9

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  1. #0

    From the perspective of prescribing antibiotics in the outpatient setting, it must be emphasized that each of the PPD resistance barriers is important, and that if one or more of these barriers cost, side- effect profile, lack of convenience, inadequate coverage of pathogens is of sufficient magnitude, it may influence the overall real- world cure rate. doxycycline for sinus infection dose

    Arrapepsy1周前 (09-18)回复
  2. #0
  3. #0

    Most of the time, mildly low thyroid hormone levels won t affect the fetus or the pregnancy, Rodi says. clomiphene moa

    BeappyKet2周前 (09-11)回复
  4. #0

    Evaluation of the efficacy and safety of once-a-day dosing of tadalafil 5 mg and 10 mg in the treatment of erectile dysfunction results of a multicenter, randomized, double-blind, placebo-controlled trial buy cialis cheap ED was reported to affect 18 million men in the United States and 189 million men globally in 2004, 193 million men in 2005, and 198 million men in 2006 8,9

    Fascish3周前 (09-08)回复
  5. #0

    One way to check this is to verify where the pharmacy is located buy cialis online from india First there was Viagra

    Itetsaups3周前 (09-06)回复
  6. #0

    壁纸插画:
    Pixivic : http://it3210.com/

    东南亚小野猫9个月前 (01-07)回复
  7. #0

    Jsososo : http://cyzhome.net/

    泡菜鱼9个月前 (12-22)回复
  8. #0
  9. #0

    http://rs0l11s.cn/
    东东博客
    在线资讯

    123cc1年前 (2021-09-18)回复