go语言需手动建模user、post、follow实体并显式声明外键(如userid uint)和gorm关联标签(如gorm:"foreignkey:userid"),http路由应按rest规范分离资源动作,请求须用结构体+binding校验,生产环境必须替换sqlite为postgresql以支持社交功能刚需。

Go 语言本身不提供“社交平台”这种现成能力,它只是帮你高效处理并发请求、组织数据结构、连接数据库和构建 HTTP 服务的工具。所谓“简易社交平台”,核心是围绕 User、Post、Follow 这几个实体设计 API 和存储逻辑,而不是堆砌框架。
用 gorm 建模用户与动态关系时,外键和关联字段必须显式声明
很多人以为加个 type Post struct { User User } 就能自动关联,其实 gorm 不会猜你意图。它只认字段名、标签和外键约束。
-
UserID uint字段不能省——这是实际存入数据库的外键值 -
User gorm.Model或User User是用于预加载(Preload)的内存结构,不参与建表 - 必须用
gorm:"foreignKey:UserID"明确告诉 GORM 关联依据,否则Preload("User")会静默失败 - 软删除(
DeletedAt)默认开启,若不需要,得在 struct 上加gorm:"index;not null"等显式控制
示例片段:
type User struct {
ID uint `gorm:"primaryKey"`
Username string `gorm:"uniqueIndex"`
Email string `gorm:"uniqueIndex"`
}
type Post struct {
ID uint `gorm:"primaryKey"`
Content string
UserID uint `gorm:"index"` // 实际外键
User User `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
CreatedAt time.Time
}
HTTP 路由设计要区分资源动作,别把所有逻辑塞进 POST /api/post
新手常把发帖、删帖、点赞、转发全扔在一个 endpoint 里,靠 body 字段判断行为。这会导致测试难、权限难控、日志难追踪。
立即学习“go语言免费学习笔记(深入)”;
-
POST /api/posts:仅创建新动态 -
DELETE /api/posts/{id}:删自己的动态(需校验userID == post.UserID) -
POST /api/posts/{id}/like:点赞(幂等性要考虑,用ON CONFLICT DO NOTHING或先查再插) -
GET /api/users/{id}/feed:个人时间线(JOIN + ORDER BY + LIMIT 分页)
路由即契约。前端调哪个地址、带什么参数、返回什么状态码,都应该在接口文档里写死,而不是靠注释或口头约定。
前端传来的 JSON 数据必须用 struct 显式解码,别直接用 map[string]interface{}
看似灵活,实则埋雷:字段名大小写错、类型不匹配、缺失必填项都会导致静默失败或 panic。
- 定义
type CreatePostRequest struct { Content string `json:"content" binding:"required,min=1,max=500"` } - 用
c.ShouldBindJSON(&req)(Gin)或json.NewDecoder(r.Body).Decode(&req)(net/http)做校验 -
binding标签能拦截空内容、超长文本、非法邮箱等,比手写 if 判断更可靠 - 错误要转成标准 HTTP 状态码:
400 Bad Request对应校验失败,401 Unauthorized对应 token 缺失
SQLite 适合开发调试,但上线前必须换成 PostgreSQL 或 MySQL
SQLite 在单机跑 demo 没问题,但它不支持行级锁、无原生 JSONB、无法水平扩展,而且 gorm.Open(sqlite.Open(...)) 的迁移行为和 PG 完全不同。
- 本地开发可用 SQLite 快速验证逻辑,但
gorm.Migrate脚本要为不同方言分别维护 - PG 支持
jsonb存标签、tsvector做全文搜索、LISTEN/NOTIFY做实时通知,这些是社交场景刚需 - 连接池配置(
SetMaxOpenConns、SetMaxIdleConns)在 PG 上必须设,SQLite 无视这些
最容易被忽略的一点:SQLite 的 time.Time 默认存成字符串,而 PG 存成 timestamptz,跨数据库迁移时时间比较会出错。










