跳到主要内容

路由

VEF 支持两种路由策略,但它们共享同一个操作模型:

  • RPC:通过 POST /api
  • REST:通过 /api/<resource>

RPC 和 REST 都是显式资源类型。RPC 资源不会自动生成 REST 路由,REST 资源也不会复用 RPC 的单端点传输模型。

路由策略总览

策略入口路径操作标识来源
RPCPOST /api请求体里的 resourceactionversion
REST/api/<resource>资源名 + action 定义的 HTTP method 和子路径

RPC 路由

RPC 请求统一进入:

POST /api

内部 router 常量 DefaultRPCEndpoint/api。form 和 multipart RPC 传输会分别从 FormKeyParamsFormKeyMeta 表单字段读取 JSON 编码的 paramsmeta

RPC 请求形态:

{
"resource": "sys/user",
"action": "find_page",
"version": "v1",
"params": {
"keyword": "tom"
},
"meta": {
"page": 1,
"size": 20
}
}

这套形态会直接映射成 api.Request

RPC 命名规则

字段规则示例
resource斜杠分段的小写资源路径usersys/userapproval/category
actionsnake_casefind_pageget_user_inforesolve_challenge
versionv<number>v1v2

RPC 传输形式

RPC 请求解析支持:

内容类型请求数据读取方式
JSON请求体直接解码为 api.Request
formresource / action / version 来自表单字段,params / meta 作为 JSON 字符串解析
multipart form与 form 相同,但上传文件会并入 params

REST 路由

REST 路由统一挂在:

/api/<resource>

挂载时,REST 路由会在 action method 转成大写、可选 sub-resource path 补上 / 前缀后,形成 /api/<resource>/<subpath>

HTTP method 和可选子路径由 action 字符串决定。

示例:

ResourceAction最终路由
usersgetGET /api/users
userspostPOST /api/users
usersget profileGET /api/users/profile
usersput profilePUT /api/users/profile
usersdelete manyDELETE /api/users/many

REST action 解析

REST action 字符串支持:

模式含义
<method>资源根路径
<method> <sub-resource>附加 kebab-case 子资源路径

解析规则:

  • method token 会在挂载时被转换为大写 HTTP method
  • 公开资源校验只接受小写 HTTP verb,以及可选的 kebab-case 子资源路径; admin/users 这类斜杠分段子路径是允许的,但每一段都必须是 kebab-case
  • /:id 这类动态 Fiber route 参数不会通过 api.ValidateActionName / api.NewRESTResource 的公开校验

REST 命名规则

字段规则示例
resource name斜杠分段的小写路径,分段内部多词使用 kebab-caseuserssys/useruser-profiles
action method token小写 HTTP verbgetpostputdeletepatch
action sub-resource可选的斜杠分段 kebab-case 路径profileadmin/usersuser-friends

框架保留的 Query Key

框架会保留一些 query key 用于自身 plumbing。REST 路由器在构建业务参数空间之前会先把它们剥离,因此它们不会出现在 params 中。

保留 key用途
__accessToken用于无法设置 Authorization 头的请求(例如浏览器 <img src> 或下载链接)传递 bearer token;认证层直接从 Fiber context 读取。

由于这些 key 被框架占用,它们不会进入业务 handler,也不会被报告为未映射键。

params 如何收集

RPC

对 RPC 请求来说:

来源最终落点
请求里的 params 对象api.Request.Params
multipart 上传文件合并进 api.Request.Params

REST

对 REST 请求来说,VEF 会把多个来源合并进 params

来源最终落点说明
path paramsparams从 Fiber route params 提取
query stringparams永远视为 params,而不是 meta
POST / PUT / PATCH 的 JSON bodyparams对象字段合并进 params
POST / PUT / PATCH 的 multipart form 字段params文本表单字段进入 params
POST / PUT / PATCH 的 multipart 上传文件params文件数组进入 params

meta 如何收集

RPC

对 RPC 请求来说,meta 直接来自请求体。

REST

对 REST 请求来说,metadata 通过 X-Meta- 前缀的 header 收集。

示例:

X-Meta-page: 1
X-Meta-size: 20
X-Meta-format: excel

这些值会进入 api.Meta

去掉 X-Meta- 前缀后,存入 meta 的 key 会统一转成小写。例如 X-Meta-pageX-Meta-Page 都会变成 meta["page"]

这里有个关键后果:

  • REST query string 仍然属于 params
  • page.Pageable 这类 typed helper 仍然从 meta 解码
  • 如果某个 REST endpoint 期望 typed metadata,就要明确告诉调用方使用 X-Meta-*

Typed 请求解码含义

Handler 参数解码来源
嵌入 api.P 的 typed structparams
嵌入 api.M 的 typed structmeta
page.Pageablemeta
api.Params原始 params
api.Meta原始 meta

因此,?page=1&size=20 并不会自动填充 typed page.Pageable,除非你把分页建模成普通 params 字段,而不是 meta。

认证解析顺序

运行时,操作的认证来源按以下顺序解析:

  1. spec.Public == true -> 公开接口
  2. 资源级 Auth() 配置
  3. API 引擎默认认证

默认引擎认证是 Bearer。

内置认证策略

VEF 当前内置这些认证策略名:

策略含义
none公开接口
bearerBearer token 认证
signature签名认证
ip来源 IP 白名单认证
api_key静态 API key 认证
http_basicRFC 7617 Basic 认证

对应 helper:

Helper含义
api.Public()公开接口
api.BearerAuth()Bearer 认证
api.SignatureAuth()签名认证
api.IPAuth(...)来源 IP 白名单认证
api.APIKeyAuth(...)API key 认证;可选自定义头名
api.HTTPBasicAuth()HTTP Basic 认证

认证输入

Bearer

Bearer token 可从以下来源读取:

来源格式
Authorization headerBearer <token>
query 参数__accessToken=<token>

Signature

Signature 认证读取:

Header含义
X-App-ID外部应用 ID
X-Timestamp请求时间戳
X-Nonce防重放 nonce
X-Signature签名值

IP

IP 认证通过 security.IPWhitelistLoader 解析命名白名单(默认实现读取 vef.security.ip_whitelists 配置)。位于反向代理之后时,需要配置 vef.app.trusted_proxies,让 Fiber 解析到真实客户端 IP。所有认证失败都会以 security.ErrIPNotAllowed 拒绝;空白名单或未找到的白名单会 fail-closed。

API key

来源格式
请求头(默认 X-API-Key,可按操作经 api.APIKeyAuth("X-My-Key") 自定义)原始密钥值

密钥经 security.APIKeyLoader 解析(默认由 vef.security.api_keys 支撑); 缺失或未匹配的密钥统一以 security.ErrAPIKeyInvalid(401)拒绝。

HTTP Basic

来源格式
Authorization headerBasic base64(username:password)

账号经 security.BasicAccountLoader 解析(默认由 vef.security.basic_accounts 支撑),常数时间比较;畸形请求头、未知账号 与错误密码统一以 security.ErrBasicCredentialsInvalid(401)拒绝。

默认操作行为

除非某个操作显式覆盖,否则 API 引擎默认会应用:

属性默认值
versionv1
timeout30s
auth strategyBearer
rate limit100 requests per 5 minutes

请求 Body 传输编码

对于 /api 表面的请求,客户端可以选择对请求 body 进行传输编码,让携带脚本或代码形态的 payload(集成适配器脚本、信封/认证脚本、dry_run body)能够穿过会对这些内容误报的中间件。编码会在调度器解析之前被解码回原始 JSON。

客户端通过请求头启用:

X-Body-Encoding: base64

或:

X-Body-Encoding: gzip+base64

支持的值:

含义
base64body 是原始 JSON 的 base64
gzip+base64body 是原始 JSON 经 gzip 压缩后再 base64(解码顺序:先 base64,再 gunzip)

原生的 Content-Encoding(如 gzipbrdeflatezstd)由 Fiber 自身解压;这个中间件只覆盖 Fiber 不认识的 base64 形式。

解码发生在 content-type 检查和调度器之前,且仅在 /api 路径上生效。存储、内容哈希缓存和审计看到的都是原始 body。body 限制(vef.app.body_limit)作用于解码后的大小,防止解压炸弹超出限制。

失败模式:

情况结果
不支持的 X-Body-Encodingapi.ErrUnsupportedBodyEncoding(HTTP 400)
base64 格式错误或 gzip 流损坏api.ErrBodyDecodeFailed(HTTP 400)
解码后的 body 超过配置限制api.ErrBodyTooLarge(HTTP 413)

响应形态

handler 通常通过 result.Ok(...)result.Err(...) 返回响应,因此 RPC 和 REST 共享同一套响应结构:

{
"code": 0,
"message": "Success",
"data": {}
}

消息文本受当前语言影响。默认语言下通常会看到 成功,切到英文后通常会看到 Success

实践建议

  • 当 API 更偏动作模型时优先用 RPC
  • 当 HTTP method 语义和路径结构更重要时优先用 REST
  • 明确文档说明分页和排序到底走 params 还是 meta
  • 不要试图掩盖 RPC 与 REST 的差异,而要把它们显式写清楚
  • 用“资源 + 操作”来思考接口,而不是只盯着 endpoint URL

下一步

继续阅读 参数与元信息,看 handler 注入使用的精确解码规则。