Files
jiang13-forum/docs/rebuild-spec/04-api.md
freefire fde5f628ec feat: opaque session、安装/发帖 SSR 与最小 Admin 后台
浏览器登录改为 DB sessions(可吊销);敏感词与 OIDC PEM 入 settings;
落地安装向导、注册发帖与 /admin 仪表盘/板块/审核/设置。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-29 05:44:16 +08:00

13 KiB
Raw Blame History

04 · HTTP API 合约

读者:机器客户端 / 集成方;浏览器 UI 使用本文件作为主路径
前置03-data-model.md08-gitea-ssr-architecture.md
源码routers/setup.gomodules/auth/auth.go

本分支(rebuild/gitea-ssr)浏览器走 routers/web 模板 + 表单
下列 JSON 合约保留作历史对照与未来机器 API当前进程仅注册 health / OIDC / robots / sitemap / media 等机器相关路由,论坛 CRUD 的 /api/* 已从路由表移除handler 源码可删可留,不以 SPA 兼容为目的)。

main 分支 SPA 仍完整实现下表;对照请 checkout main


1. 本分支已注册的机器入口

方法 路径 说明
GET /health 探活
GET /robots.txt 抓取规则
GET /sitemap.xml 站点地图
GET/POST /oauth/*/.well-known/openid-configuration OIDC Provider
GET /media/thumb/*/uploads/* 媒体

2. 历史 JSON 合约main / 对照,本分支默认不挂载)

以下章节描述原 SPA 使用的 /api 形状,便于迁移业务语义;实现 UI 时请用 web 表单,勿恢复双轨。

通用约定(历史)

约定
Base 同源;credentials: 'same-origin'
成功 HTTP 2xx + JSON body
失败 非 2xx + { "error": "..." }
鉴权 Cookie jiang13_sessionopaque机器 OIDC 用 Bearer

分页形态差异

场景 典型字段
前台帖列表 posts, total, page, size, has_more
后台多数列表 total, page, total_pages + 实体数组
私信会话消息 before 游标式

3. 基础设施 / SEO / 静态(节选,仍有效)

方法 路径 鉴权 说明
GET /health { "status": "ok" }
GET /robots.txt 文本
GET /sitemap.xml XML
GET /media/thumb/*filepath 缩略图 / WebP 等
GET /uploads/* 静态上传文件

3. OIDC Provider

方法 路径 鉴权 说明
GET /.well-known/openid-configuration Discovery
GET /oauth/jwks JWKS
GET /oauth/authorize OptionalAuth 授权码流程
POST /oauth/token 无(客户端凭证) 换 token
GET/POST /oauth/userinfo Bearer 用户信息
GET/POST /oauth/logout 视实现 登出

细节以 service/oidc.go / handler/oidc.go 为准。


4. 公开 API/api + OptionalAuth

4.1 会话与站点

方法 路径 响应要点
GET /api/me { user: UserSelf | null }
GET /api/stats { users, posts, boards, comments }
GET /api/forum-limits ForumLimitsPublic(无限流内部字段)
GET /api/site-branding SiteBranding(可含 site_url
GET /api/captcha { id, image } image 为 data URL 或 base64
GET /api/register/config 见下

RegisterConfig

{
  "is_first_user": true,
  "mail_ready": false,
  "require_email_code": false,
  "register_open": true,
  "email_code_len": 6
}

4.2 认证(限流)

方法 路径 Body 响应
POST /api/register Form: username, password, nickname, email, email_code? 成功后通常种 cookie
POST /api/login Form: username, password 种 cookie
POST /api/register/email-code JSON { email } { message }
POST /api/password-reset/email-code JSON { email } { message }
POST /api/password-reset JSON { email, email_code, new_password } { message }

4.3 内容只读

方法 路径 Query / 说明
GET /api/boards { boards: Board[] }
GET /api/posts 见下表
GET /api/posts/hot 热门列表
GET /api/posts/:id skip_view=1 可选;返回 PostDetailResponse
GET /api/posts/:id/comments my_ids 可选(逗号分隔,便于标自己的楼)
GET /api/tags limit 默认 40 → { tags: [{name,count}] }
GET /api/comments/recent { comments: RecentComment[] }
GET /api/users/search q, limit
GET /api/users/recent { users: RecentUser[] }
GET /api/users/:id { user: UserPublic, stats }
GET /api/pages 已发布摘要列表
GET /api/pages/:slug 单页详情
GET /api/projects page, limit, q

GET /api/posts Query

参数 说明
page 默认 1
size 默认 page_size_default上限 100
board_id 0 或不传=全部
user_id 某用户的帖
keyword 搜索词
tag 标签
author 用户名优先,否则昵称精确匹配
title_only 1/true 仅搜标题
sort latest | reply | hot

响应示例

{
  "posts": [ /* PostItem */ ],
  "total": 100,
  "page": 1,
  "size": 30,
  "has_more": true
}

PostDetailResponse 要点

{
  "post": { /* PostItem + content */ },
  "comment_count": 0,
  "liked": false,
  "favorited": false,
  "has_replied": false,
  "can_edit": true,
  "edit_block_reason": "",
  "is_edited": false,
  "post_edit_window_hours": 24,
  "poll": { /* PollView 可选 */ },
  "lottery": { /* PostLotteryView 可选 */ },
  "bounty_can_refund": false,
  "bounty_refund_block_reason": "",
  "bounty_eligible_reply_count": 0
}

4.4 游客可写评论

方法 路径 限流 Body
POST /api/posts/:id/comments comment Form: content, reply_to?, is_private?, 以及游客字段(以实现为准)

登录用户发评也走此路径RequireAuth 组外公开组已注册该路由)。


5. 需登录 API/api + RequireAuth

5.1 会话与资料

方法 路径 Body 响应
POST /api/logout 清 cookie
GET /api/favorites { favorites, total }
GET /api/profile/stats { stats: UserActivityStats }
POST /api/profile/nickname Form nickname
POST /api/profile/signature Form signature { message, user }
POST /api/profile/password Form old_password, new_password
POST /api/profile/avatar Form avatar=file { avatar }
POST /api/uploads/image Form image=file { url }

5.2 帖子写操作

方法 路径 Body 响应
POST /api/posts Form: board_id, title, content, tags?, post_type?, poll_options?, bounty_points?, lottery_winner_count? { message, post_id, status }
PUT /api/posts/:id Form: title, content, tags?, board_id?, post_type? { message }
DELETE /api/posts/:id 软删
GET /api/posts/:id/revisions { revisions }
GET /api/posts/:id/revisions/:revId { revision }
POST /api/posts/:id/like { liked, like_count }
POST /api/posts/:id/favorite { favorited }
POST /api/posts/:id/resolve Form resolved=1|0 { question_resolved }
POST /api/posts/:id/poll/vote JSON { option_ids: number[] } { poll }
POST /api/posts/:id/poll/close { poll }
POST /api/posts/:id/bounty/award Form comment_id
POST /api/posts/:id/bounty/refund
POST /api/posts/:id/lottery/draw { lottery }
POST /api/posts/:id/report JSON { reason, detail? } { report }
POST /api/posts/:id/unlock JSON { block_key } 见下

poll_options JSON 示例Form 字段字符串)

{
  "multi": false,
  "max_choices": 1,
  "ends_at": "2026-09-01T12:00:00Z",
  "options": [{ "text": "选项A" }, { "text": "选项B" }]
}

unlock 响应

{
  "message": "...",
  "unlock": {
    "block_key": "abcdef0123456789",
    "cost": 10,
    "points_balance": 90,
    "inner_html": "<p>...</p>"
  }
}

5.3 评论写操作

方法 路径 Body
POST /api/comments/:id/like { liked, like_count }
POST /api/comments/:id/report JSON { reason, detail? }
PUT /api/comments/:id Form content
DELETE /api/comments/:id

5.4 私信

方法 路径 说明
GET /api/messages/unread-count { count, dm_count?, notify_count? }
GET /api/messages/notifications page, size, kind
POST /api/messages/notifications/read
GET /api/messages/conversations page, size
GET /api/messages/conversations/:peerId size, beforepeerId=0 为系统
POST /api/messages/conversations/:peerId/read
POST /api/messages JSON { to_user_id, subject?, content }
POST /api/messages/read-all

5.5 经济

方法 路径 说明
GET /api/me/points page含 ledger、check_in、lottery
GET/POST /api/me/check-in 状态 / 执行签到
GET/POST /api/me/lottery 状态 / 抽奖

5.6 友链申请

方法 路径 Body
POST /api/friend-links/apply JSON name, url, logo, link_on_homepage, reciprocal_page_url?
POST /api/friend-links/logo Form logo=file → { url }
GET /api/friend-links/my-applies
PUT /api/friend-links/applies/:id 同申请字段
DELETE /api/friend-links/applies/:id 取消

6. 管理 API/api/admin + Auth + Admin

6.1 仪表盘与设置

方法 路径 说明
GET /dashboard AdminDashboard
GET /settings AdminSettings 聚合
PUT /settings/forum ForumLimits
PUT /settings/mail MailConfig
POST /settings/mail/test { to }
PUT /settings/oidc OIDCConfig
PUT /settings/gitea 后置501
POST /settings/gitea/sync 后置501
PUT /settings/storage StorageConfig
PUT /settings/branding SiteBranding
POST /settings/branding/upload Form kind=logo|favicon|og_image, file
POST /settings/branding/clear JSON { kind }
GET/PUT /settings/filter-words GET 读PUT { content }

(上表路径均相对于 /api/admin。)

6.2 OAuth 客户端

方法 路径
GET/POST /oauth/clients
PUT/DELETE /oauth/clients/:id

创建/更新 bodyname, redirect_uris, client_id?, enabled?, client_secret?, rotate_secret?

6.3 板块 / 单页 / 友链

方法 路径
POST/PUT/DELETE /boards, /boards/:id
GET/POST /pages
GET/PUT/DELETE /pages/:id
PUT /pages/:id/published{ published }
GET /friend-link-applies
PUT /friend-link-settings
POST /friend-link-applies/:id/approve | reject | recheck

6.4 帖子审核与运营

方法 路径 Body
GET /posts page, keyword, status
GET /posts/trash
POST /posts/:id/pin { pinned }
POST /posts/:id/board-pin { board_pinned }
POST /posts/:id/feature { featured }
POST /posts/:id/lock { locked } → edit_locked
POST /posts/:id/comments-lock { locked }
POST /posts/:id/approve
POST /posts/:id/reject { reason }
POST /posts/:id/restore
DELETE /posts/:id/purge 硬删
DELETE /posts/:id 软删

6.5 评论 / 举报 / 用户 / 徽章 / 媒体 / 备份

方法 路径 说明
GET /comments, /comments/trash
GET /comments/:id/revisions
POST /comments/:id/approve | reject | restore reject 可带 reason
DELETE /comments/:id, /comments/:id/purge
GET /reports page, status
POST /reports/:id/handle { action, handle_note?, reject_reason? }action=dismiss|resolve|reject_post|reject_comment
GET /users page, keyword, filter
POST /users/:id/ban { banned }
POST /users/:id/verify { verified }
POST /users/:id/level { level }
POST /users/:id/points { delta, note? }
POST /users/:id/badges { badge_id, revoke? }
GET/POST /badges 列表 / upsert
GET /media category, page, size, q
POST /media/delete { urls: string[] }
POST /backup { filename, download }
GET /backup/download/:name 文件下载

7. 核心类型速查(与前端对齐)

详见 [frontend/src/api/types.ts]((仅 mainfrontend/src/api/types.ts)。实现时至少对齐:

  • User / UserPublic / UserActivityStats
  • Board / PostItem / PostDetailResponse / Comment
  • ForumLimits / ForumLimitsPublic / SiteBranding
  • PollView / PostLotteryView
  • PrivateMessage / MessageConversation
  • PostReport / FriendLinkApply / BadgeDef / PointLedger
  • CheckInStatus / LotteryStatus
  • AdminDashboard / AdminSettings / StorageConfig / MailConfig / OIDCConfig

8. 鉴权错误语义(现网)

中间件对未登录 / 过期 / 禁言返回 JSON error并可能清 cookie。前端统一 throw new Error(data.error)。新站应保持可区分的错误文案或错误码,避免前端无法提示。

源:middleware/auth.go