用unidoc生成带中文PDF时乱码,需显式注册中文字体(如NotoSansCJKsc-Regular.otf),推荐用embed.FS打包字体并调用pdf.AddTTFFontFromBytes传入字节切片,再通过cell.SetFont指定已注册字体名。

用 unidoc 生成带中文的 PDF 时乱码怎么办
Go 原生不支持 PDF 生成,必须依赖第三方库;unidoc 是目前少数能稳定处理中文字体嵌入的方案,但默认不加载字体,直接写中文会变成方块或空格。
关键不是“选哪个库”,而是“怎么让字体进 PDF”:
-
unidoc要求显式注册字体文件(如NotoSansCJKsc-Regular.otf),不能只靠系统字体路径 - 字体文件需随二进制一起分发,推荐用
embed.FS打包进程序,避免运行时路径错误 - 注册时用
pdf.AddTTFFontFromBytes,传入字节切片而非文件路径,否则在 Docker 或无权限目录下失败 - 中文内容必须用已注册的字体名(如
"NotoSansCJKsc-Regular")调用cell.SetFont或text.SetFont,不能依赖默认字体
gofpdf 导出大表格时内存暴涨甚至 OOM
gofpdf 简单易上手,但所有绘图操作都累积在内存中的 *gofpdf.Fpdf 实例里,导出千行以上表格时,未及时分页或复用对象会导致内存持续增长。
实操要点:
- 每 50–100 行主动调用
pdf.AddPage(),避免单页过大;用pdf.GetY()判断剩余空间,比硬编码行数更可靠 - 避免反复创建
gofpdf.New实例——它本身不重,但内部缓存和状态叠加后会拖慢 - 表格单元格内容用
CellFormat而非多次Cell+SetXY,减少坐标计算开销 - 导出前调用
pdf.Close()触发最终写入,否则Output可能返回不完整数据
HTTP 响应中导出 PDF 文件名含中文就乱码
浏览器对 Content-Disposition 中的中文文件名解析不一致:Chrome 支持 filename*=UTF-8''xxx,Safari 和旧版 Edge 只认 filename 的 ASCII 编码(如 base64 或 RFC 5987 格式)。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
稳妥做法是双写头:
header := w.Header()
header.Set("Content-Type", "application/pdf")
header.Set("Content-Disposition",
`attachment; filename="report.pdf"; filename*=UTF-8''`+url.PathEscape("报表-"+time.Now().Format("20060102")+".pdf"))
注意:url.PathEscape 处理的是 UTF-8 字节序列,不是字符串直接拼接;若用 strconv.Quote 或手动 hex 编码,反而会失效。
生成 PDF 后无法在 iOS Safari 打开或提示“无效文件”
常见原因不是内容问题,而是 HTTP 响应缺少关键头或缓冲未刷新:
- 必须设置
Content-Length(尤其 Nginx 反代时),否则 iOS Safari 拒绝渲染流式响应 - 用
http.ServeContent替代直接w.Write,它会自动补全头、处理 range 请求、校验 ETag - 确保 PDF 字节流完整:调用
pdf.Output后检查 error,空 slice 或 panic 会导致输出 0 字节 - 测试时用
curl -I看响应头,确认Content-Length与实际字节数一致,且无Transfer-Encoding: chunked
字体嵌入、分页逻辑、HTTP 头三者任一出错,都会让 PDF 在特定环境静默失败——不能只看本地 Chrome 能打开就认为没问题。


















