安全处理文章api需:①开头校验json并解码;②路径参数用strconv.parseint强转;③写操作严格校验http方法;④单条查用queryrow.scan,列表用query+rows.next;⑤json输出字段首字母大写并加json tag,null字段用sql.nullx并判.valid。

Go 的 http.HandlerFunc 怎么安全处理文章增删改查
直接用 http.HandlerFunc 写内容 API 最容易掉进「状态裸奔」和「参数校验缺失」两个坑。比如 POST 新文章时没校验 Title 非空,或 DELETE 时只靠 URL 路径里的 id 就删库,没核对用户权限和资源归属。
实操建议:
- 每个 handler 开头先做
json.NewDecoder(r.Body).Decode(&req)+if err != nil { http.Error(w, "invalid json", 400) },别信前端传来的任何结构体字段顺序或类型 - URL 路径参数(如
/api/articles/{id})必须用chi.URLParam(r, "id")或手动从r.URL.Path提取,再强转为int64—— Go 的strconv.Atoi遇到非数字会 panic,得用strconv.ParseInt(x, 10, 64) - 所有写操作(POST/PUT/DELETE)必须检查
r.Method == "POST"等,别依赖前端 header;CSRF 不是重点,但方法校验是底线
用 database/sql 操作文章表时,Scan 和 QueryRow 哪个更稳
QueryRow 更适合单条文章读取(如 GET /api/articles/123),Scan 配合 Rows 迭代更适合列表(GET /api/articles?limit=20)。错用会导致 panic 或漏数据。
常见错误现象:
立即学习“go语言免费学习笔记(深入)”;
- 用
QueryRow().Scan()查列表 → 只扫第一行,其余被丢弃,还可能因 no rows 报sql.ErrNoRows - 用
Query().Scan()直接扫单行 → panic:“sql: expected 1 destination argument, got X” - struct 字段没加
db:"title"tag,Scan 时字段全零值,但不报错
实操建议:
- 查单条:用
err := db.QueryRow("SELECT id,title,... FROM articles WHERE id = ?", id).Scan(&a.ID, &a.Title, ...) - 查列表:用
rows, _ := db.Query("SELECT ..."); defer rows.Close(); for rows.Next() { rows.Scan(&a.ID, ...) } - struct 字段 tag 必须和 SELECT 字段顺序、类型严格一致;时间字段优先用
time.Time,别用 string
为什么 json.Marshal 返回空对象或乱码,而不是文章数据
根本原因就两个:struct 字段未导出(小写开头),或数据库查出来是 nil 指针没解引用。不是编码问题,是 Go 的反射规则和 SQL 扫描逻辑在打架。
mallcloud商城基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba并采用前后端分离vue的企业级微服务敏捷开发系统架构。并引入组件化的思想实现高内聚低耦合,项目代码简洁注释丰富上手容易,适合学习和企业中使用。真正实现了基于RBAC、jwt和oauth2的无状态统一权限认证的解决方案,面向互联网设计同时适合B端和C端用户,支持CI/CD多环境部署,并提
使用场景典型例子:
- 定义
type Article struct { id int; Title string }→json.Marshal后是{},因为id小写不可见 - 数据库字段允许 NULL(如
summary TEXT NULL),用sql.NullString接收,但忘了判断.Valid就直接json.Marshal→ summary 字段消失或变空字符串 - struct 里嵌了另一个 struct(如
Author AuthorInfo),但AuthorInfo里有未导出字段 → 整个Author在 JSON 里为空对象
实操建议:
- 所有要 JSON 输出的字段名首字母大写,且加
json:"title,omitempty"tag;omitempty可避免零值污染响应 - NULL 字段统一用
sql.NullString/sql.NullTime,marshal 前做转换:Summary: a.Summary.String(注意 String 方法返回空串而非 panic) - 别在 struct 里直接 embed
sql.Rows或*sql.Rows—— 它们不能被 JSON 序列化
Gin 或 chi 路由里怎么传 context 给数据库层而不全局变量
用全局 var db *sql.DB 是可行的,但一旦要加请求级 trace ID、用户身份或超时控制,就必须把 context.Context 从 handler 一路透传到 db.QueryContext。否则并发下日志串、超时失效、权限混淆。
性能影响很实际:不用 Context 的查询无法被 cancel,一个慢查询会卡住整个 goroutine,而带 ctx 的可以设 ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second)。
实操建议:
- handler 里不要直接调
db.Query,而是封装一层GetArticle(ctx context.Context, id int64) (*Article, error) - 数据库操作函数第一参数永远是
ctx,内部用db.QueryRowContext(ctx, ...)替代QueryRow - 别用
context.Background()补位;如果 handler 没传 ctx,宁可 panic 也不硬造 —— 这能暴露设计断点
最常被忽略的是:中间件注入的 value(比如用户 ID)也要通过 context.WithValue 往下传,而不是塞进全局 map。value key 必须是自定义类型,别用 string,否则跨包冲突。









