Skip to content

自定义路由

POST /cell 之外的 HTTP 需求——GET 直链下载、健康检查、支付异步回调、文件上传——用 BindRoute 承接。v1.3.0 起支持通配符路径。

注册

go
func (f *Fun) BindRoute(method, path string, handler RouteHandler, guardList ...Guard) error
  • 须在 Start 前注册;
  • method 大小写不敏感;path 必须以 / 开头、精确匹配,或以 /* 结尾做前缀通配;
  • /cell 为 RPC 保留路径,不可注册;
  • 重复注册或非法参数启动期 panic;Guard 依赖装配失败以 error 返回。

RouteCtx

go
type RouteCtx struct {
    RequestCtx *fasthttp.RequestCtx // 原生 fasthttp 上下文
    Data       map[string]string    // URL 查询参数 + POST 表单参数(表单优先)
    Wildcard   string               // 通配符路由匹配到的剩余路径(不含前导 "/")
}

func (c *RouteCtx) Param(name string) string // 取查询/表单参数,不存在返回空串

处理器签名:

go
type RouteHandler func(ctx *RouteCtx) error
  • 返回 nil:视为已自行写回响应(可完全自定义状态码与内容),框架不再写任何东西;
  • 返回 error:框架统一输出 Result 错误响应(fun.Error 可带码)。

示例:健康检查与直链

go
// 纯文本应答
f.BindRoute("GET", "/healthz", func(c *fun.RouteCtx) error {
    c.RequestCtx.WriteString("ok")
    return nil // 已写响应
})

// 通配符:GET /image/a/b.png → Wildcard == "a/b.png"
f.BindRoute("GET", "/image/*", func(c *fun.RouteCtx) error {
    key := c.Wildcard
    data, err := loadObject(key)
    if err != nil {
        return fun.Error(4044, "对象不存在") // 统一 Result 错误
    }
    c.RequestCtx.Write(data)
    return nil
})

精确路由优先于通配符:同时注册 /image/avatar.png/image/* 时,前者先命中。

示例:支付异步回调

第三方支付网关以 form-urlencoded 回调、要求纯文本应答的场景:

go
f.BindRoute("POST", "/pay/notify", func(c *fun.RouteCtx) error {
    // Param 已合并查询参数与表单参数,直接取值
    if c.Param("trade_status") != "TRADE_SUCCESS" {
        return fun.Error(4001, "invalid status")
    }
    // ... 按网关要求验签、幂等处理 ...

    c.RequestCtx.WriteString("success") // 网关要求的纯文本应答
    return nil
})

Param 只解析 urlencoded

Param 合并的是查询串与 application/x-www-form-urlencoded 表单(表单优先)。multipart 不合并——文件上传场景见下节。

大请求体与 multipart 上传(v1.3.3+)

默认请求体上限是 fasthttp 的 4MB。大体积 multipart 上传用 SetBodyLimit 放宽,处理器里经原生 RequestCtx 读 multipart:

go
f.SetBodyLimit(64 << 20) // 64MB;传 0 或负数恢复默认 4MB

f.BindRoute("POST", "/upload", func(c *fun.RouteCtx) error {
    form, err := c.RequestCtx.MultipartForm()
    if err != nil {
        return fun.Error(4001, "invalid multipart")
    }
    file := form.File["file"][0]
    // ... 保存文件 ...
    c.RequestCtx.WriteString("uploaded")
    return nil
})

普通 RPC(/cell)场景不需要文件直传:前端把小文件转 base64 放进 DTO 即可。

路由级 Guard

go
f.BindRoute("GET", "/admin/*", handler, &AuthGuard{})
  • 处理器前按注册顺序执行,返回 error 短路(处理器不执行,错误走统一 Result);
  • Guard 的 Ctx.State 已合并 URL 查询与表单参数——token 放查询参数即可鉴权。

匹配规则速查

规则行为
/healthz精确匹配(尾斜杠敏感)
/image/*前缀匹配 /image/ 下任意子路径,剩余路径进 Wildcard
精确 vs 通配精确优先
/cell保留,注册 panic
未匹配路径404;方法不匹配 405
注册时机必须在 Start

下一步

基于 MIT 许可发布