All skills
gogf avatar

/goframe-v2

@911705d
by GoFramegogf/skills81 stars
3

GoFrame v2 development skill. Use only when the target Go project uses or is explicitly adopting GoFrame v2: the nearest go.mod requires github.com/gogf/gf/v2, existing Go files import github.com/gogf/gf/v2 or any github.com/gogf/gf/v2/... component package, or the user asks to scaffold, migrate, or build with GoFrame. Trigger for GoFrame-backed Go work such as APIs/controllers/services, middleware, routing/config, ORM/DAO/DO/entity/database operations, gf CLI/codegen, HTTP/gRPC services, and microservice conventions. Do not trigger for generic Go projects without GoFrame evidence, frontend-only work, shell scripts, or unrelated infrastructure tasks.

Use this Skill: https://skilld.dev/gh/gogf/skills/goframe-v2

This session only. Nothing lands on disk.

referencesWEB服务开发路由管理路由管理-中间件拦截器中间件拦截器-使用示例.md

允许跨域请求

第一个例子,也是比较常见的功能需求。

我们需要在所有API请求之前增加允许跨域请求的返回 Header 信息,该功能可以通过中间件实现:

package main

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

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

func main() {
    s := g.Server()
    s.Group("/api.v2", func(group *ghttp.RouterGroup) {
        group.Middleware(MiddlewareCORS)
        group.ALL("/user/list", func(r *ghttp.Request) {
            r.Response.Writeln("list")
        })
    })
    s.SetPort(8199)
    s.Run()
}

执行后,终端打印出路由表信息如下:

SERVER | DOMAIN  | ADDRESS | METHOD |       ROUTE       |      HANDLER      |     MIDDLEWARE
|---------|---------|---------|--------|-------------------|-------------------|---------------------|
  default | default | :8199   | ALL    | /api.v2/user/list | main.main.func1.1 | main.MiddlewareCORS
|---------|---------|---------|--------|-------------------|-------------------|---------------------|

这里我们使用 group.Middleware(MiddlewareCORS) 将跨域中间件通过分组路由的形式注册绑定到了 /api.v2 路由下所有的服务函数中。随后我们可以通过请求 http://127.0.0.1:8199/api.v2/user/list 来查看允许跨域请求的 Header 信息是否有返回。

请求鉴权处理

我们在跨域请求中间件的基础之上加上鉴权中间件。

为了简化示例,在该示例中,当请求带有 token 参数,并且参数值为 123456 时可以通过鉴权,并且允许跨域请求,执行请求方法;否则返回 403 Forbidden 状态码。

package main

import (
    "net/http"

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

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

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

func main() {
    s := g.Server()
    s.Group("/api.v2", func(group *ghttp.RouterGroup) {
        group.Middleware(MiddlewareCORS, MiddlewareAuth)
        group.ALL("/user/list", func(r *ghttp.Request) {
            r.Response.Writeln("list")
        })
    })
    s.SetPort(8199)
    s.Run()
}

执行后,终端打印出路由表信息如下:

SERVER | DOMAIN  | ADDRESS | METHOD |       ROUTE       |      HANDLER      |               MIDDLEWARE
|---------|---------|---------|--------|-------------------|-------------------|-----------------------------------------|
  default | default | :8199   | ALL    | /api.v2/user/list | main.main.func1.1 | main.MiddlewareCORS,main.MiddlewareAuth
|---------|---------|---------|--------|-------------------|-------------------|-----------------------------------------|

可以看到,我们的服务方法绑定了两个中间件,跨域中间件和而鉴权中间件。 请求时将会按照中间件注册的先后顺序,先执行 MiddlewareCORS 全局中间件,再执行 MiddlewareAuth 分组中间件。 随后我们可以通过请求 http://127.0.0.1:8199/api.v2/user/list 和 http://127.0.0.1:8199/api.v2/user/list?token=123456 对比来查看效果。

鉴权例外处理

使用分组路由中间件可以很方便地添加鉴权例外,因为只有当前分组路由下注册的服务方法才会绑定并执行鉴权中间件,否则并不会执行到鉴权中间件。

package main

import (
    "net/http"

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

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

func main() {
    s := g.Server()
    s.Group("/admin", func(group *ghttp.RouterGroup) {
        group.ALL("/login", func(r *ghttp.Request) {
            r.Response.Writeln("login")
        })
        group.Group("/", func(group *ghttp.RouterGroup) {
            group.Middleware(MiddlewareAuth)
            group.ALL("/dashboard", func(r *ghttp.Request) {
                r.Response.Writeln("dashboard")
            })
        })
    })
    s.SetPort(8199)
    s.Run()
}

执行后,终端打印出路由表信息如下:

SERVER | ADDRESS | DOMAIN  | METHOD | P |      ROUTE       |       HANDLER       |     MIDDLEWARE
|---------|---------|---------|--------|---|------------------|---------------------|---------------------|
  default |  :8199  | default |  ALL   | 2 | /admin/dashboard | main.main.func1.2.1 | main.MiddlewareAuth
|---------|---------|---------|--------|---|------------------|---------------------|---------------------|
  default |  :8199  | default |  ALL   | 2 | /admin/login     | main.main.func1.1   |
|---------|---------|---------|--------|---|------------------|---------------------|---------------------|

可以看到,只有 /admin/dashboard 路由的服务方法绑定了鉴权中间件 main.MiddlewareAuth,而 /admin/login 路由的服务方法并没有添加鉴权处理。 随后我们访问以下URL查看效果:

  1. http://127.0.0.1:8199/admin/login
  2. http://127.0.0.1:8199/admin/dashboard
  3. http://127.0.0.1:8199/admin/dashboard?token=123456

统一的错误处理

基于中间件,我们可以在服务函数执行完成后做一些后置判断的工作,特别是统一数据格式返回、结果处理、错误判断等等。这种需求我们可以使用后置的中间件类型来实现。我们使用一个简单的例子,用来演示如何使用中间件对所有的接口请求做后置判断处理,作为一个抛砖引玉作用。

package main

import (
    "net/http"

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

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

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

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.Use(MiddlewareCORS)
    s.Group("/api.v2", func(group *ghttp.RouterGroup) {
        group.Middleware(MiddlewareAuth, MiddlewareErrorHandler)
        group.ALL("/user/list", func(r *ghttp.Request) {
            panic("db error: sql is xxxxxxx")
        })
    })
    s.SetPort(8199)
    s.Run()
}

执行后,终端打印出路由表信息如下:

SERVER | DOMAIN  | ADDRESS | METHOD |       ROUTE       |       HANDLER       |                   MIDDLEWARE
|---------|---------|---------|--------|-------------------|---------------------|-------------------------------------------------|
  default | default | :8199   | ALL    | /*                | main.MiddlewareCORS | GLOBAL MIDDLEWARE
|---------|---------|---------|--------|-------------------|---------------------|-------------------------------------------------|
  default | default | :8199   | ALL    | /api.v2/user/list | main.main.func1.1   | main.MiddlewareAuth,main.MiddlewareErrorHandler
|---------|---------|---------|--------|-------------------|---------------------|-------------------------------------------------|

在该示例中,我们在后置中间件中判断有无系统错误,如果有则返回固定的提示信息,而不是把敏感的报错信息展示给用户。当然,在真实的项目场景中,往往还有是需要解析返回缓冲区的数据,例如 JSON 数据,根据当前的执行结果进行封装返回固定的数据格式等等。

执行该示例后,访问 http://127.0.0.1:8199/api.v2/user/list?token=123456 查看效果。

自定义日志处理

我们来更进一步完善一下以上示例,我们将请求日志包括状态码输出到终端。这里我们必须得使用”全局中间件”了,这样可以拦截处理到所有的服务请求,甚至 404 请求。

package main

import (
    "net/http"

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

func MiddlewareAuth(r *ghttp.Request) {
    token := r.Get("token")
    if token.String() == "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()
    errStr := ""
    if err := r.GetError(); err != nil {
        errStr = err.Error()
    }
    g.Log().Println(r.Response.Status, r.URL.Path, errStr)
}

func main() {
    s := g.Server()
    s.SetConfigWithMap(g.Map{
        "AccessLogEnabled": false,
        "ErrorLogEnabled":  false,
    })
    s.Use(MiddlewareLog, MiddlewareCORS)
    s.Group("/api.v2", func(group *ghttp.RouterGroup) {
        group.Middleware(MiddlewareAuth)
        group.ALL("/user/list", func(r *ghttp.Request) {
            panic("啊!我出错了!")
        })
    })
    s.SetPort(8199)
    s.Run()
}

可以看到,我们注册了一个全局的日志处理中间件以及跨域中间件,而鉴权中间件是注册到 /api.v2 路由下。

执行后,我们可以通过请求 http://127.0.0.1:8199/api.v2/user/list 和 http://127.0.0.1:8199/api.v2/user/list?token=123456 对比来查看效果,并查看终端的日志输出情况。

Source: SKILL.md on GitHub

1 alert16d5 checks · Risk MEDIUM
  • Gen Agent Trust Hub16d

    The skill provides a comprehensive development guide and code examples for the GoFrame v2 framework. While highly informative for Go developers, it contains several examples with hardcoded placeholder secrets, tokens, and specific local file paths to sensitive configuration files (like Kubernetes credentials). These elements are provided for demonstration purposes but represent insecure practices if used in production without modification.

  • Socket16d

    5 alerts: gptSecurity, gptAnomaly

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    227/949 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 911705d. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 4 months ago.

Steadyupdated 4 months ago
  • Go
  • Database
  • goframe
  • orm
  • http
  • grpc
  • microservices
  • crud
  • scaffolding
  • middleware

README badge

README badge for gogf/skills

Provides instruction and conventions for developing with GoFrame v2, a modular Go framework for building HTTP and gRPC services, microservices, and database operations using its ORM, CLI tooling, and project scaffolding. Use this skill when the target project has GoFrame v2 as a dependency or when the user requests scaffolding, migrations, or service development with GoFrame conventions.

Generated from the current SKILL.md.

When should I use this skill?
Use this skill only when your Go project uses GoFrame v2, indicated by github.com/gogf/gf/v2 in go.mod or imports. Do not use for generic Go projects, frontend work, or infrastructure tasks unrelated to GoFrame.
Should I manually set created_at and updated_at fields?
No. GoFrame automatically writes created_at on insert and updated_at on insert/update/save. Manually setting these fields is redundant and violates project conventions.
What should I use for database operations instead of g.Map?
Always use DO objects from internal/model/do/. DO struct fields are interface{}, unset fields remain nil and are automatically ignored by the ORM.
How does soft delete work in GoFrame?
Call Delete() on the DAO; GoFrame automatically converts it to UPDATE SET deleted_at = NOW(). Queries automatically filter out soft-deleted rows without requiring manual WhereNull conditions.
Where should I implement business logic?
Implement business logic directly in the service/ directory. Do not use the logic/ directory unless explicitly requested.

Generated from the current SKILL.md. These answers refresh after source changes.