Files
go_blog/handlers/api.go
T
kevin b1e9d9cae6 feat: API 基建——/api JSON 接口统一契约与认证分支
- handlers/api.go:APIOK/APIError/bindJSON,统一 {ok,redirect,data} /
  {ok:false,code,error} 响应契约(code=i18n 键,error 按请求语言翻译)
- i18n:新增 api_error/api_unauthorized/api_forbidden/api_invalid_request(中英)
- middleware/auth.go:AuthRequired/AdminRequired 按 /api 前缀分支:
  JSON 401/403(页面保持 302),新增 isAPIRequest + apiAuthError
- main.go:路由注册提取为 registerRoutes;建立 /api 分组并搬移附件三件套
  (admin/my)与 /api/profile/avatar(旧 /admin|my/articles/attachments、
  /profile/avatar 路由移除)
- handlers/login_ratelimit.go:loginRateLimiter 导出为 LoginRateLimiter
- templates/layouts/base.html:blogAPI/blogForm/blogShowError 共享 fetch 助手
- main_test.go:TestRegisterRoutesSmoke 冒烟测试(注册期 gin 静态/参数
  冲突即 panic + 关键 /api 路由断言)
- go build/vet/test ./... 全绿
2026-08-27 19:24:43 +08:00

53 lines
1.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package handlers
import (
"net/http"
"github.com/gin-gonic/gin"
)
// APIOK 返回统一成功响应。
// redirect 非空时附带相对跳转地址(原 302 目标,可含 ?saved=1 等 query);
// data 额外字段会合并进响应。
func APIOK(c *gin.Context, redirect string, data gin.H) {
resp := gin.H{"ok": true}
if redirect != "" {
resp["redirect"] = redirect
}
for k, v := range data {
resp[k] = v
}
c.JSON(http.StatusOK, resp)
}
// APIError 返回统一错误响应:{ok:false, code, error}。
// trKey 是 i18n 键,直接作为 code 返回;error 为该键按请求语言的翻译文案。
// trKey 为空时回退到通用键 "api_error"。
func APIError(c *gin.Context, status int, trKey string) {
tr := getTr(c)
code := trKey
if code == "" {
code = "api_error"
}
msg := tr[code]
if msg == "" {
msg = tr["api_error"]
}
c.JSON(status, gin.H{
"ok": false,
"code": code,
"error": msg,
})
}
// bindJSON 将 JSON 请求体绑定到 v。
// 绑定失败时返回 400 + api_invalid_request,并返回 false。
// 使用前必须保证请求是 JSONContent-Type: application/json)。
func bindJSON(c *gin.Context, v interface{}) bool {
if err := c.ShouldBindJSON(v); err != nil {
APIError(c, http.StatusBadRequest, "api_invalid_request")
return false
}
return true
}