Rails 5中用Wicked-PDF生成PDF直接上传AWS S3遇报错问题
解决Wicked-PDF生成的PDF直接上传AWS S3的问题
问题原因
你碰到的ArgumentError: string contains null byte错误,本质是因为Aws::S3::Object#upload_file这个方法是专门用来上传本地文件的——它接受的参数是本地文件路径字符串,或者一个File对象。当你直接把Wicked-PDF生成的二进制PDF字符串传进去时,SDK会误把这个二进制内容当作文件路径去解析,而PDF二进制里的null字节会导致路径解析失败,所以抛出了错误。
解决方案:直接上传二进制内容(无需本地存储)
完全不需要先把PDF存到本地文件夹,直接用S3 SDK的put方法就能上传生成的二进制字符串,这是更高效的方式:
# 生成PDF二进制字符串 pdf = render_to_string pdf: "some_file_name", template: "invoices/download", encoding: "UTF-8" # 初始化S3资源 s3 = Aws::S3::Resource.new(region: ENV['AWS_REGION']) obj = s3.bucket('bucket-development').object('your-invoice-filename.pdf') # 直接上传PDF内容,同时指定正确的文件类型 obj.put( body: pdf, content_type: 'application/pdf', # 让S3正确识别这是PDF文件 content_disposition: 'attachment; filename="your-invoice-filename.pdf"' # 可选:设置用户下载时显示的文件名 )
为什么存本地后上传能成功?
当你把PDF内容写入本地文件,再把文件路径传给upload_file时,SDK会正确读取这个本地文件的二进制内容,而不是把路径当作内容解析,自然就不会触发null字节的错误。但直接上传内容省去了本地文件的写入、清理步骤,显然更简洁高效。
额外小提示
- 如果你的发票PDF体积特别大,可以考虑用S3的分块上传功能,但普通发票的大小用
put方法完全足够。 - 记得确认你的AWS权限配置正确,应用需要拥有目标S3桶的
PutObject权限。
内容的提问来源于stack exchange,提问作者almo




