使用FileReader发送原始文件数据到Redmine时附件损坏如何解决?
问题根因
代码的核心问题出在使用FileReader.readAsBinaryString()读取文件后直接传递字符串给POST请求:
readAsBinaryString()返回的是UTF-16编码的DOMString字符串,不是原始二进制字节流- 前端HTTP请求库默认会把字符串类型的请求体自动转码为UTF-8格式传输,这个过程会修改所有非ASCII范围的原始字节值,导致最终传到Redmine的文件内容和原文件不一致,出现损坏。
修复方案
方案1:直接传递File对象(最简便)
现代浏览器和主流请求库(axios、fetch等)都支持直接把File对象作为请求体传递,不需要额外用FileReader读取,请求库会自动处理二进制传输,代码可以简化为:
await this.$api.post(`${this.url}?filename=${file.name}`, file, { headers: { 'X-Redmine-API-Key': 'xxxxxxxxxxxxxxxxx', 'Content-Type': 'application/octet-stream', }, })
方案2:用ArrayBuffer传递(必须使用FileReader的场景)
如果你的场景需要先读取文件内容再传输,改用readAsArrayBuffer读取,拿到的就是原始二进制字节流,不会触发自动转码:
const reader = new FileReader() reader.onload = async () => { const fileContent = reader.result // 此处为ArrayBuffer类型,不是字符串 await this.$api.post(`${this.url}?filename=${file.name}`, fileContent, { headers: { 'X-Redmine-API-Key': 'xxxxxxxxxxxxxxxxx', 'Content-Type': 'application/octet-stream', }, }) } reader.readAsArrayBuffer(file)
额外注意
如果请求库默认开启了请求数据序列化,需要给当前接口关闭序列化配置,避免框架篡改二进制请求体。
内容的提问来源于stack exchange,提问作者Mathieu Tristan
相关产品推荐
相关产品推荐

