Echo Server:帖子系统从 0 到 1

第三阶段:补齐社区项目核心 CRUD,完成发帖、查帖、删帖和 token 鉴权

社区项目CRUD鉴权

0. 为什么必须补这一页

评论、点赞和统计聚合都依赖帖子系统。如果只写创建 posts 表就跳到评论点赞,读者会不知道 post_id 从哪里来,也不知道删除权限如何判断。

项目说明
建议位置精选作品详情页 / 项目文档页
统一风格左侧导航、右侧正文、表格说明、折叠代码块、阶段总结。
阅读顺序建议从总览页进入,再按卡片顺序阅读。

1. posts 表设计

posts 表保存发帖人、正文、图片、创建时间,并通过外键关联 users。

CREATE TABLE IF NOT EXISTS posts (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  user_id BIGINT NOT NULL,
  content TEXT NOT NULL,
  image_url VARCHAR(255) DEFAULT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  INDEX idx_posts_user_id (user_id),
  INDEX idx_posts_created_at (created_at),
  INDEX idx_posts_id (id),
  CONSTRAINT fk_posts_user_id
    FOREIGN KEY (user_id) REFERENCES users(id)
    ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2. token 鉴权辅助函数

发帖和删帖不能相信客户端传来的 user_id,必须从 Authorization 请求头里的 demo_token 解析当前用户。

long long getUserIdFromRequest(const HttpRequestPtr& req) {
    std::string auth = req->getHeader("Authorization");
    std::string prefix = "Bearer demo_token_";

    if (auth.rfind(prefix, 0) != 0) {
        return -1;
    }

    std::string idStr = auth.substr(prefix.size());
    try {
        return std::stoll(idStr);
    } catch (...) {
        return -1;
    }
}

3. 接口设计

建议统一使用 /api/posts 前缀,并保持复数形式。

POST /api/posts/create
请求头:Authorization: Bearer demo_token_用户ID
请求体:{"content":"第一条帖子","image_url":""}

GET /api/posts/latest?page=1&page_size=20
返回:最新帖子列表

GET /api/posts/user?user_id=1&page=1&page_size=20
返回:指定用户主页帖子列表

GET /api/posts/detail?post_id=1
返回:帖子详情

POST /api/posts/delete
请求头:Authorization: Bearer demo_token_用户ID
请求体:{"post_id":1}

4. 联调测试命令

按登录、发帖、查最新、查用户主页、查详情、删帖的顺序测试。

TOKEN="demo_token_1"

curl -s -X POST http://127.0.0.1:8080/api/posts/create   -H "Content-Type: application/json"   -H "Authorization: Bearer $TOKEN"   -d '{"content":"这是第一条帖子","image_url":""}' | jq

curl -s "http://127.0.0.1:8080/api/posts/latest?page=1&page_size=20" | jq
curl -s "http://127.0.0.1:8080/api/posts/user?user_id=1&page=1&page_size=20" | jq
curl -s "http://127.0.0.1:8080/api/posts/detail?post_id=1" | jq

curl -s -X POST http://127.0.0.1:8080/api/posts/delete   -H "Content-Type: application/json"   -H "Authorization: Bearer $TOKEN"   -d '{"post_id":1}' | jq