beego本身不生成pdf,需配合gofpdf等库;关键在正确设置content-type为application/pdf、用servebinary发送字节流、避免文本方法误发二进制数据。

Beego 框架本身不生成 PDF,它只负责 HTTP 响应;真正出问题的地方,90% 是响应头没设对、二进制数据被当文本发出去了。
Beego 中用 gofpdf 生成 PDF 后浏览器打不开?
常见现象是 Chrome 显示“无法加载 PDF”或空白页,Firefox 提示“文件已损坏”,其实 PDF 内容完全正确,只是浏览器没认出来。
-
Content-Type必须设为application/pdf,不能留空、不能是text/plain或application/octet-stream -
Content-Disposition推荐设为attachment; filename="report.pdf",否则部分浏览器(如旧版 Safari)会尝试内嵌渲染但失败 - PDF 库(如
gofpdf)输出的是[]byte,必须用ctx.Ctx.ResponseWriter.Write()或ctx.ServeBinary()发送,禁用ctx.String()和ctx.JSON() - 别在生成后调
pdf.OutputFileAndClose("xxx.pdf")再读磁盘——多一次 I/O,还可能因权限/路径报错
示例关键段:
pdf := gofpdf.New("P", "mm", "A4", "")
pdf.AddPage()
pdf.SetFont("Arial", "", 12)
pdf.Cell(40, 10, "Report for "+username)
buf := new(bytes.Buffer)
pdf.Output(buf)
ctx.Ctx.ResponseWriter.Header().Set("Content-Type", "application/pdf")
ctx.Ctx.ResponseWriter.Header().Set("Content-Disposition", "attachment; filename=report.pdf")
ctx.ServeBinary(buf.Bytes(), "report.pdf")
Beego Controller 里怎么传动态数据进 PDF 模板?
gofpdf 不支持 HTML 模板,但你可以用 text/template 先渲染文字内容,再写入 PDF;或者改用支持 HTML 的库(如 wkhtmltopdf 封装),但后者需额外服务依赖。
- 推荐方式:用
text/template渲染纯文本段落,再逐行用pdf.MultiCell()写入 - 模板函数可注册进
template.FuncMap,比如金额格式化:"formatMoney": func(v float64) string { return fmt.Sprintf("$%.2f", v) } - 注意:PDF 坐标系和字体编码限制多,中文需显式加载 UTF-8 字体(如
pdf.AddUTF8Font()),否则显示方块 - 避免在模板里做复杂逻辑,PDF 渲染是单次顺序写入,不支持回溯或重排版
并发导出 PDF 时内存暴涨甚至 OOM?
每次生成都新建 gofpdf 实例 + bytes.Buffer,高并发下 buf 累积不释放,尤其当 PDF 较大(含图表、图片)时更明显。
- 不要复用
gofpdf.Fpdf实例(它不是 goroutine-safe) - 用
sync.Pool复用*bytes.Buffer,初始化时设好容量(如bytes.NewBuffer(make([]byte, 0, 64) - 生成完立即调
buf.Reset()并归还到 Pool,别等 GC - 超大报表考虑流式生成 +
io.Pipe,但 Beego 的ServeBinary不支持流,得换用ctx.Ctx.ResponseWriter直接写
最易被忽略的一点:Beego 的 ServeBinary 会自动设置 Content-Length,但如果中间有中间件(如 gzip、日志)提前读了 ResponseWriter,可能导致 header 被冻结、Content-Type 生效失败——务必确认没有其他中间件干扰写响应流程。











