微信小程序调用go后端时post拿不到body,需显式解析:json用json.newdecoder(r.body).decode(),表单用r.parseform();code2session须get+url参数且严格校验格式;openid存redis配随机token,禁存session_key;生产必须https,建议nginx终止tls。

微信小程序调用 Go 后端时,POST 请求拿不到 body 怎么办
Go 默认的 http.Request 不会自动解析 application/json 或 application/x-www-form-urlencoded 的请求体,小程序发过来的 JSON 数据会“卡”在缓冲区里,r.Body 读出来是空的或报 http: request body too large。
常见错误现象:json.Unmarshal(r.Body, &v) 解析失败、r.FormValue("xxx") 返回空字符串、日志里看到 Content-Length: 123 但 io.ReadAll(r.Body) 读到空字节。
- 必须显式调用
r.ParseForm()(仅对urlencoded有效)或r.ParseMultipartForm()(上传文件时),否则r.PostForm和r.FormValue都不可用 - 处理 JSON 时别直接读
r.Body两次——第一次读完后r.Body就 EOF 了;要用io.ReadAll一次性读完再解析 - 小程序默认发的是
application/json,Go 后端别依赖r.FormValue,老老实实用json.NewDecoder(r.Body).Decode(&v) - 如果用了 Gin/Echo 等框架,它们内部已做处理,但自建
http.ServeMux时这点最容易漏
小程序登录态校验:用 code2Session 接口验 session_key 时为啥总返回 invalid appid
不是 AppID 写错了,而是请求参数没按微信要求拼——code2Session 是 GET 请求,所有参数必须作为 URL 查询参数传,且 appid、secret、js_code、grant_type 缺一不可,顺序无关但大小写敏感。
典型翻车点:secret 从环境变量读出来带换行符、js_code 从小程序 login 成功回调里取值时没 trim 空格、URL 拼接时忘了 url.QueryEscape 处理中文或特殊字符。
- 微信接口地址必须是
https://api.weixin.qq.com/sns/jscode2session,不能少sns/,也不能写成https://api.weixin.qq.com/cgi-bin/... -
grant_type只能是字符串"authorization_code",不是"code"也不是"auth_code" - 用
net/http发请求时,别用http.Post——它发的是 POST,而code2Session要 GET;改用http.Get或构造*http.Request手动设Method = "GET" - 响应要检查
err == nil且resp.StatusCode == 200,再解析 JSON;微信出错时也返回 200,但 body 里有errcode字段
Go 后端怎么安全存用户 openid 和 session_key
别存 session_key ——它本就是临时密钥,有效期约 2 小时,且微信明确不建议长期存储;真正该持久化的是 openid(用户唯一标识),配合自产的短期 token 做本地会话管理。
常见错误:把 session_key 当作登录凭证存在 Redis 里,过期后无法刷新;或者把 openid 直接当 API Token 透传给前端,导致账号被撞库或冒用。
- 收到
code2Session响应后,只提取openid和unionid(如果绑定了开放平台),丢掉session_key - 用
crypto/rand生成 32 字节随机 token,和openid一起存 Redis,设置 TTL(比如 7 天),key 格式建议token:<token_hex></token_hex> - 小程序每次请求带上自定义 header
X-Auth-Token,后端查 Redis 验证是否存在对应openid,不碰微信任何密钥 - 避免用 Go 的
time.Now().Unix()做 token,容易被预测;也不要用math/rand,它不加密安全
部署时 http: TLS handshake error 导致小程序请求 400
小程序强制要求后端 HTTPS,但本地开发用 http.ListenAndServe(":8080", nil) 是 HTTP;上线后若用 Nginx 反向代理但没配好 TLS 终止,或证书链不全,Go 进程本身又没启 HTTPS,就会在日志里刷 TLS handshake error,小程序客户端收不到响应,表现为超时或 400 错误。
这不是 Go 代码问题,是基础设施层配置偏差。微信校验域名时会走完整 TLS 握手,任何环节断开都会失败。
- 生产环境别让 Go 直接跑 HTTPS——用 Nginx/Apache 做 TLS 终止,Go 后端只监听
localhost:8080的 HTTP,更轻量也更安全 - Nginx 配置里必须包含
ssl_certificate和ssl_certificate_key,且证书文件得是 PEM 格式,不能是 PFX 或 JKS - 检查证书是否由可信 CA 签发(Let’s Encrypt 可以,自签不行),用
openssl s_client -connect yourdomain.com:443看输出里有没有Verify return code: 0 (ok) - 小程序后台配置的服务器域名,必须和证书里的
Subject Alternative Name完全一致,不支持泛域名匹配(*.a.com不认api.a.com)
最麻烦的其实是证书更新后 Nginx 没 reload,或者 DNS 解析还没切到新 IP——这些地方查起来比写 Go 代码还花时间。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











