最简路径是用 qrcode.Encode 得 *image.NRGBA,再用 png.Encode 写入 http.ResponseWriter;须前置设置 Content-Type、确保 UTF-8 编码、传正确像素尺寸与容错等级。

用 qrcode 库生成 PNG 二维码最简路径
Go 生态里最轻量、无 CGO 依赖的二维码生成方案是 qrcode 库(github.com/skip2/go-qrcode)。它不依赖图像处理底层库,纯 Go 实现,适合 API 场景。
常见错误是直接调用 qrcode.WriteFile 写磁盘——API 接口不该落盘,得走内存流转。正确做法是用 qrcode.Encode 得到 *image.NRGBA,再用 png.Encode 写入 http.ResponseWriter。
-
qrcode.Encode第三个参数是像素尺寸(如256),不是 DPI;传太小(如16)会导致二维码无法被扫描 - 容错等级用
qrcode.Low/qrcode.Medium等常量,别传数字,否则编译不通过 - 中文内容必须 UTF-8 编码,库本身不处理编码转换,传入前确保字符串已是 UTF-8 字节流
HTTP handler 中避免 image/png 响应头遗漏或错位
生成完二维码图后,响应头顺序和值直接影响前端能否正常显示。漏设 Content-Type 或写在 Write 之后,浏览器会当文本渲染乱码。
典型错误:在 png.Encode 后才调用 w.Header().Set("Content-Type", "image/png")——此时 header 已隐式写出,设置无效。
立即学习“go语言免费学习笔记(深入)”;
- 务必在任何
w.Write或编码操作前调用w.Header().Set("Content-Type", "image/png") - 可加
w.Header().Set("Cache-Control", "no-store")防止 CDN 缓存动态码 - 若需支持 CORS,补上
Access-Control-Allow-Origin: *,但生产环境建议限定域名
并发场景下 qrcode 库是否线程安全?
是的,qrcode.Encode 和所有导出函数都是无状态的,内部不共享可变全局变量,可被任意 goroutine 并发调用。
但要注意:如果你封装了复用的 *png.Encoder 或自定义 image.ColorModel,那些对象本身不是并发安全的——别跨 goroutine 复用实例。
- 每次请求都新建
bytes.Buffer和调用png.Encode,别试图池化png.Encoder - 如果 QPS 极高(>5k/s),瓶颈通常在 PNG 编码环节,此时可考虑预生成固定内容的二维码并缓存 byte slice,而非优化库调用
- 别用
sync.Pool缓存*image.NRGBA,它的Bounds()尺寸随输入变化,池化收益低且易引发尺寸错乱
为什么不用 github.com/disintegration/imaging 或 golang.org/x/image?
这些库擅长通用图像处理(缩放、滤镜、格式转换),但生成二维码是特定逻辑,引入它们反而增加构建体积、CGO 依赖(如 imaging 依赖 libjpeg)和部署复杂度。
除非你要在二维码上叠加 Logo、加圆角边框或做透视变换,否则纯用 qrcode + 标准库 image/draw 就够用——后者无额外依赖,且 draw.Draw 支持 Alpha 合成。
- 加 logo 示例:用
qrcode.Encode得图 A,用imaging.Open("logo.png")得图 B,再用draw.Draw把 B 画到 A 中心区域 - 别用
golang.org/x/image/font给二维码加文字——字体渲染会显著拖慢 API 延迟,且移动端扫码引擎通常忽略二维码内文字 - 所有图像操作务必检查
bounds,比如 logo 尺寸超过二维码 20%,会导致扫码失败










