You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask读取PostgreSQL中bytea类型PDF下载报错问题排查

问题原因

下载得到的PDF空白、格式错误,本质是三个常见问题:

  • psycopg2默认读取PostgreSQL的bytea类型字段时,返回的是数据库hex编码后的字节序列(默认以\x作为前缀,不是PDF的原始二进制流)。比如原始PDF开头的%PDF-格式标识会被编码为\x255044462d,直接把这个编码后的内容写入文件,PDF阅读器无法识别格式,自然显示空白或损坏。
  • 调用send_file时未指定application/pdf的MIME类型,部分浏览器/客户端会按默认文本类型处理响应,额外注入字符或修改内容,进一步损坏文件。
  • 现有代码未释放数据库游标、连接资源,高并发场景下会触发数据库连接泄漏。

快速验证方式:把下载的损坏PDF用文本编辑器打开,如果文件开头是\x拼接的十六进制字符串,就可以确认是bytea编码未解码的问题。

修复代码

先在数据库连接层面配置bytea输出格式,同时兼容处理可能存在的hex编码前缀,指定正确的响应MIME类型,补全资源释放逻辑:

from flask import send_file
from io import BytesIO
import psycopg2
import psycopg2.extras

@app.route('/download_file')
def downloadFile():
    conn = None
    cur = None
    try:
        # 替换为你实际的数据库连接参数
        conn = psycopg2.connect(
            host="你的数据库地址",
            dbname="你的库名",
            user="你的账号",
            password="你的密码"
        )
        cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
        # 配置数据库直接返回原始bytea二进制,不做hex转义
        cur.execute("SET bytea_output = 'escape';")
        
        # 实际业务可从请求参数动态获取fail_id,例:fail_id = request.args.get("fail_id", type=int)
        fail_id = 9
        # 用参数化查询,避免SQL注入和二进制转义问题
        cur.execute("SELECT email_pdf FROM fails WHERE fail_id = %s", (fail_id,))
        row = cur.fetchone()
        if not row or not row["email_pdf"]:
            return "指定文件不存在", 404
        
        pdf_content = row["email_pdf"]
        # 兼容兜底:如果返回内容带\x的hex前缀,手动解码为原始二进制
        if pdf_content.startswith(b'\\x'):
            pdf_content = bytes.fromhex(pdf_content[2:].decode("ascii"))
        
        return send_file(
            BytesIO(pdf_content),
            mimetype="application/pdf",
            as_attachment=True,
            download_name="new.pdf"
        )
    except Exception as e:
        return f"文件下载失败:{str(e)}", 500
    finally:
        # 必须释放数据库资源
        if cur:
            cur.close()
        if conn:
            conn.close()
额外排查项

如果按上述代码修改后文件仍然损坏,需要检查PDF写入数据库的逻辑:

  • 写入bytea字段时,必须传入PDF文件的原始二进制bytes对象,不能将二进制内容做utf-8/gbk等文本解码后再存储,否则会不可逆破坏PDF格式
  • 写入时必须使用psycopg2的参数化查询传值,不要手动拼接SQL字符串,避免特殊字符被转义损坏

内容的提问来源于stack exchange,提问作者hekuma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 08:36:26