Go-qrcode是轻量纯Go二维码库,用qrcode.Encode(text,level,size)生成PNG字节流,需设Content-Type: image/png;支持自定义颜色需qrcode.New()+WriteTo();注意尺寸≥100、校验URL防攻击、监控高纠错或大尺寸导致的延迟。

Go-qrcode 生成二维码的基本用法
Go-qrcode 是一个轻量、纯 Go 实现的 QR 码生成库,不依赖外部 C 库,适合嵌入 HTTP 服务中直接返回图片。它默认输出 png 格式字节流,可直接写入 http.ResponseWriter。
安装命令是:go get github.com/skip2/go-qrcode。注意不要用旧版 github.com/boombuler/barcode,后者已归档且不支持自定义颜色和容错等级。
-
qrcode.Encode()是最常用函数,接收字符串、尺寸(像素)、纠错等级三个参数,返回[]byte和 error - 尺寸指整个图像宽高(单位 px),不是模块大小;最小值为 100,否则生成失败并报
qrcode: size too small - 纠错等级用
qrcode.Low/qrcode.Medium/qrcode.High/qrcode.Highest表示,推荐qrcode.Medium平衡容错与码密度
在 HTTP Handler 中直接返回 PNG 二维码
别把二维码先存文件或转 base64——既慢又浪费内存。直接设置响应头 + 写入字节流即可。
关键点:必须设 Content-Type: image/png,否则浏览器当文本打开显示乱码;同时建议加 Cache-Control 减少重复请求。
立即学习“go语言免费学习笔记(深入)”;
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
func qrcodeHandler(w http.ResponseWriter, r *http.Request) {
text := r.URL.Query().Get("url")
if text == "" {
http.Error(w, "missing 'url' param", http.StatusBadRequest)
return
}
pngBytes, err := qrcode.Encode(text, qrcode.Medium, 256)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "image/png")
w.Header().Set("Cache-Control", "public, max-age=3600")
w.Write(pngBytes)
}
- URL 参数要校验合法性,防止 SSRF 或注入攻击;生产环境建议白名单域名过滤
- 尺寸 256 是常见移动端适配值;若需高清屏显示,可按设备 dpr 动态放大(如 2× 尺寸),但注意生成耗时随像素数平方增长
- 不要用
fmt.Fprint(w, ...)输出,会触发文本编码,导致 PNG 头损坏
自定义前景色、背景色与边距
原生 qrcode.Encode() 不支持样式定制。要用 qrcode.WriteTo() 配合 image/png.Encode() 手动控制画布。
核心思路:用 qrcode.New() 创建编码器 → 调 Encode() 得到 *image.Gray → 在新 *image.RGBA 上绘制带颜色的点阵 → 写入响应。
qr, err := qrcode.New(text, qrcode.Medium)
if err != nil { return }
qr.DisableBorder = true // 去除默认白边(注意:这是 go-qrcode v1.3+ 才有)
img := image.NewRGBA(image.Rect(0, 0, qr.Size, qr.Size))
// 设置背景色(例如 #ffffff)
for y := 0; y < qr.Size; y++ {
for x := 0; x < qr.Size; x++ {
img.Set(x, y, color.RGBA{255, 255, 255, 255})
}
}
// 绘制黑色模块(#000000)
for y := 0; y < qr.Size; y++ {
for x := 0; x < qr.Size; x++ {
if qr.QRCode.Black(y, x) {
img.Set(x, y, color.RGBA{0, 0, 0, 255})
}
}
}
w.Header().Set("Content-Type", "image/png")
png.Encode(w, img)
-
DisableBorder = true才能精确控制边距;否则默认留 4 模块白边,无法通过缩放消除 - 颜色值用
color.RGBA,Alpha 必须设为 255,否则 PNG 透明通道可能被浏览器错误渲染 - 性能敏感场景慎用此方式:纯色填充双循环比
qrcode.Encode()慢 3–5 倍,QPS 下降明显
并发安全与内存注意事项
qrcode.Encode() 是无状态函数,本身线程安全;但高频生成时,PNG 编码过程会分配大量临时内存,GC 压力上升。
实测单次 256×256 生成约分配 1.2MB 内存,若每秒 100 次请求,即产生 120MB/s 的短生命周期对象——容易触发频繁 GC,造成延迟毛刺。
- 对固定内容(如 App 下载页)建议预生成并缓存
[]byte,用sync.Map存 key→pngBytes - 避免在 handler 里做字符串拼接构造 URL(如
"https://example.com/?ref=" + uid),应使用net/url.Values防止非法字符污染二维码内容 - 超大尺寸(>1024)或超高纠错(
Highest)会使生成时间从毫秒级升至数十毫秒,需监控 p99 延迟
真正难的是平衡样式需求和性能损耗——加 logo、改颜色、留白控制,每一步都在增加 CPU 和内存开销,而用户扫不出来时,通常不会怪颜色不好看,只会说“扫不了”。

















