正确姿势是先URL解码再调用qrcode.Encode生成[]byte,设置Content-Type为image/png后写入响应;需校验长度、加内存缓存、配置CORS且确保HTTPS。

go-qrcode 生成二维码图片的正确姿势
直接用 qrcode.Encode 得到的是 []byte,不是 HTTP 响应能直接吐出去的图片——常见错误是拿它当字符串返回,结果浏览器显示一堆乱码或报 MIME type not supported。
- 必须手动设置响应头:
w.Header().Set("Content-Type", "image/png") -
qrcode.Encode第三个参数是尺寸(像素),别传 0 或负数,否则 panic;推荐固定用256或512,太小扫不出来,太大没意义 - 内容编码默认是 UTF-8,如果传入含控制字符或空字节的字符串,会失败并返回
qrcode: content contains invalid characters - 示例:
img, _ := qrcode.Encode("https://example.com", qrcode.Medium, 256) w.Header().Set("Content-Type", "image/png") w.Write(img)
HTTP 路由里处理 query 参数的坑
很多人把 text 直接从 r.URL.Query().Get("text") 拿出来就 encode,但没做 URL 解码——比如前端传 text=https%3A%2F%2Fgolang.org,不 decode 就会扫出错链接。
- 务必用
url.QueryUnescape处理后再传给qrcode.Encode - 空值或超长值(如 > 2KB)要拦截,
go-qrcode对超长内容支持弱,容易卡住或返回空白图 - 建议加长度限制:
if len(text) > 2048 { http.Error(w, "text too long", http.StatusBadRequest); return }
并发高时 CPU 占用飙升的原因和缓解方式
go-qrcode 底层是纯 Go 实现的 QR 编码 + PNG 渲染,没用 CGO,但每个请求都重算整个矩阵+绘图,压测时 CPU 100% 很常见。
- 不要在 handler 里反复调用
qrcode.New或自定义配置——复用一个全局*qrcode.QRCode实例没用,它不缓存中间结果 - 真正有效的办法是加内存缓存:用
text+size当 key,缓存生成好的[]byte图片(注意控制 TTL 和总大小) - 如果允许降级,可提前预热常用链接(如官网、下载页)到缓存中
- 避免在循环里生成多个码——批量需求建议改用
github.com/boombuler/barcode配合并发池
跨域和 HTTPS 场景下的实际限制
前端 JS 用 fetch 调这个 API 时,如果服务没开 CORS,会触发预检失败;更隐蔽的问题是:某些扫码 App(尤其微信内嵌浏览器)拒绝加载非 HTTPS 的二维码图片资源。
立即学习“go语言免费学习笔记(深入)”;
- 必须加 CORS 头:
w.Header().Set("Access-Control-Allow-Origin", "*")(生产环境建议限定域名) - 如果后端跑在 HTTP,但前端是 HTTPS 页面,Chrome 会直接屏蔽图片请求,控制台报
Mixed Content—— 这时候只能上反向代理或强制服务走 HTTPS - 二维码内容本身含 HTTP 链接也没关系,只要图片资源地址是 HTTPS 就行










