用户注册接口至少需username、password、email三个必填字段,须校验长度、格式(如邮箱合法性)、密码强度,并做数据库唯一性检查、密码哈希存储及并发安全处理。

注册接口需要哪些基础字段和校验
用户注册至少得收 username、password、email,缺一不可。Fiber 本身不带表单验证,得靠 schema 或手动检查——别依赖前端传来的数据,后端必须重验。
常见踩坑:只校验邮箱格式却没查数据库是否已存在;密码明文存库;password 字段没做长度限制(建议 8–64 位)。
- 用
strings.TrimSpace()清掉用户名前后空格,否则"admin "和"admin"被当成两个用户 - 邮箱统一转小写再入库,避免
USER@EXAMPLE.COM和user@example.com重复注册 - 密码不能直接存
req.Body里的原始值,必须用bcrpyt.GenerateFromPassword()哈希
用 Fiber 的 ctx.BodyParser() 解析 JSON 请求
别手写 json.Unmarshal(),Fiber 提供的 BodyParser() 更省事,但要注意结构体字段必须导出(首字母大写),且加 json: tag。
错误现象:BodyParser() 返回 nil 错误但字段全是零值——大概率是结构体字段没导出或 tag 拼错。
type RegisterRequest struct {
Username string `json:"username"`
Email string `json:"email"`
Password string `json:"password"`
}
- 调用前先检查
ctx.Request().Header.Get("Content-Type")是否为application/json,否则直接返回 400 - 解析失败时用
ctx.Status(400).JSON(fiber.Map{"error": "invalid request body"}),别 panic - 别在解析后还用
ctx.Body()二次读取,Fiber 的 Body 是单次读取流,第二次会为空
插入数据库前必须查重并处理并发注册
用 SELECT ... FOR UPDATE 或唯一索引 + 捕获冲突错误更可靠。单纯 SELECT 再 INSERT 有竞态风险——两个请求同时查到“用户名不存在”,然后都插入成功。
PostgreSQL 示例:建唯一索引 CREATE UNIQUE INDEX idx_users_email ON users(email),然后捕获 pg.ErrUniqueViolation;MySQL 对应 mysql.ErrDupEntry。
- 查重 SQL 必须覆盖所有唯一约束字段(比如 username 和 email 都要单独查)
- 不要用
INSERT IGNORE或ON CONFLICT DO NOTHING后再查影响行数——它不报错也不告诉你哪条冲突,调试困难 - 查重和插入尽量放在同一个事务里,避免中间被其他操作插入同名用户
密码哈希和响应处理的细节
用 golang.org/x/crypto/bcrypt,别自己拼 salt。哈希成本因子设为 12 左右,太高拖慢登录,太低不安全。
注册成功后,别把密码、token 或数据库 ID 直接塞进响应体返回给前端——只返回必要字段,比如 {"id": 123, "username": "foo", "created_at": "..."}。
-
bcrypt.GenerateFromPassword([]byte(req.Password), 12)返回的是[]byte,存库前记得转成string(它本身是 ASCII 字符串) - 如果后续要发邮件激活,别在注册接口里同步调用 SMTP——用消息队列或异步 goroutine,否则用户等太久
- HTTP 状态码用
201 Created,不是200 OK,符合 REST 语义
Fiber 注册接口真正难的不是写几行路由,而是并发下的数据一致性、密码安全边界、以及错误反馈是否暴露过多服务细节——比如数据库唯一键名、字段长度限制这些,都不该透出给前端。











