Revel 框架需借助第三方库 qrcode(simeji)生成二维码,推荐直接操作 http.ResponseWriter 输出 PNG/SVG,注意设置 ContentType、纠错等级、长度校验及并发安全。

Revel 框架本身不内置二维码生成能力,得靠第三方库拼装。Go 生态里最常用的是 qrcode(by simeji),轻量、无 CGO 依赖、支持 PNG/SVG/ASCII 输出,和 Revel 配合很顺。
安装 qrcode 并注册为 Revel 依赖
先加依赖:
go get github.com/simeji/qrcode
Revel 不像 Gin 那样直接 return []byte,它走的是 Result 接口。所以不能只调 qrcode.Write 就完事,得包装成自定义 Result 或手动写响应体。推荐后者——更可控、避免中间层封装失真。
- 别用
qrcode.New后反复调Encode:每次都会重新计算 Reed-Solomon 码字,高并发下有性能抖动 - 别把
qrcode.QRCode实例全局复用:它不是线程安全的,多个 goroutine 并发调Write可能 panic - 如果要用 SVG,注意
qrcode.WriteSVG返回的是io.Writer,需用bytes.Buffer中转再写入c.Response.Out
在 Revel Controller 里输出 PNG 二维码
核心是绕过 Revel 的模板渲染流程,直接操作 http.ResponseWriter:
func (c App) Qr(data string) revel.Result {
if data == "" {
c.Response.Status = 400
return c.RenderError("data is required")
}
qr, err := qrcode.New(data, qrcode.Low)
if err != nil {
c.Response.Status = 500
return c.RenderError(err.Error())
}
// 设置响应头
c.Response.ContentType = "image/png"
// 直接写入响应流
err = qr.Write(png.Writer(c.Response.Out))
if err != nil {
c.Response.Status = 500
return c.RenderError("failed to write qr image")
}
return nil
}
-
qrcode.Low对应纠错等级 L(7%),适合 URL 类短内容;传参可改为qrcode.High提升容错但体积略增 -
png.Writer是qrcode库自带的 PNG 编码器,无需额外引入image/png - 别漏掉
c.Response.ContentType = "image/png",否则浏览器可能当文本下载或乱码显示
支持动态参数与错误防护
真实接口要防滥用,比如限制长度、过滤控制字符、拒绝空格开头的 data:
- URL 参数建议用
c.Params.Get("data")而非c.Params.Route.Get("data"),前者支持 query string,后者只取路由段 - 对
data做strings.TrimSpace+len([]rune(data)) <= 2953(QR Code 版本 40 字节上限) - 若需带 logo 水印,
qrcode库不支持,得用golang.org/x/image/draw手动合成,注意 PNG 解码+重绘会增加 CPU 开销 - 高并发场景建议加简单限流,比如用
golang.org/x/time/rate.Limiter控制每秒请求数,避免 PNG 渲染压垮 goroutine
真正难的不是生成一张图,而是让每个请求都稳定返回正确尺寸、正确 MIME 类型、不卡住连接。Revel 的 Result 抽象容易让人忽略底层 HTTP 流控,直接写 c.Response.Out 反而更贴近本质。别被框架名字带偏——它只是个路由器和依赖注入器,图像输出这事,还是得亲手握紧 http.ResponseWriter。


















