英文:
Downloading ZIP file using NodeJS and ReactJS
问题
My React client sends a request to download a zip file created on the backend (Node JS) server. When I print the post response, I see a string resembling a zip file content, but the downloaded file is corrupted and cannot be opened by zip applications. The backend method, however, saves a correctly functioning zip file for debugging. What could be the issue with my React client POST response?
英文:
I am trying to download a zip file using a ReactJS client. The zip file is created at backend side (Node JS).
My React client does the following:
{this.state.selectedRows.length > 0 &&
<>
<Tooltip title="Baixar arquivos" arrow>
<IconButton
onClick={() => {
const dcs = (!!this.state.selectedRows && this.state.selectedRows.length === 0) ? this.state.fls.map(f => f.doc_id ) : this.state.selectedRows
this.props.api.post('/mediateca/downloadzipfile', { docs: dcs }).then(r => {
this.setState({ selectedRows: [] })
var blob = new Blob([r], { type: "application/octet-stream" });
saveAs(blob, "example.zip")
})
}}>
<FileDownload />
</IconButton>
</Tooltip>
<D size="0.5rem" />
</>
}
If I print the post response ( "console.log(r)") I see a string like "PK<0x03><0x04><0x14>...", but longer (it seems to be the ASCII sequence of a zip file). I makes the download example.zip file with 238,2 kB. However, no zip application is able to open it.
More over, at backend Node JS side, I have the post route triggering this method:
async downloadZIPfile(ctx) {
let u = await ctx.auth.getUser()
Log.create(!!u ? u.email : "null", ctx.request.url())
const { docs } = ctx.request.all()
const rdocs = !!docs && docs.length > 0 ? docs : []
//Recupera os pdfs do banco de dados e salva um zip no /tmp
if(rdocs.length > 0){
var zip = new AdmZip()
for(let x in rdocs){
const doc = await Documentos.findOne({ where: { id: rdocs[x] } })
if (!!doc) {
const file = await Arquivos.findOne({ where: { id: doc.arquivo_id } })
var filePath = "/tmp/"+rdocs[x]+".pdf"
zip.addFile(rdocs[x]+".pdf",file.binario)
}
}
var data = zip.toBuffer()
var fileName = "flavio.zip"
zip.writeZip("/tmp/"+fileName)
ctx.response.header('Content-Type', 'application/octet-stream')
ctx.response.header('Content-Disposition', `attachment; filename=${fileName}`)
ctx.response.header('Content-Length', data.length)
ctx.response.send(data);
}
else {
ctx.response.status(404).send()
}
return { status: 'ok' }
}
}
Note that this method saves a flavio.zip 130,8KB file for debugging. It can be opened correctly by any zip application.
So, what is wrong with my React client POST response?
I am trying to download a zip file using a ReactJS client. The zip file is created at backend side (Node JS).
答案1
得分: 0
问题可能出在你在ReactJS客户端中处理响应的方式上。不要直接将响应数据传递给saveAs函数,而是应该从响应数据创建一个新的Blob对象,然后将其传递给saveAs函数。
在这段代码中,我们将responseType选项设置为'arraybuffer',以便响应数据以ArrayBuffer对象的形式返回,然后我们可以使用它来创建一个新的Blob对象。我们将这个Blob对象和所需的文件名传递给saveAs函数以触发下载。
英文:
the issue might be with how you're handling the response in your ReactJS client. Instead of directly passing the response data to the saveAs function, you should create a new Blob object from the response data and then pass that to the saveAs function.
this.props.api.post('/mediateca/downloadzipfile', { docs: dcs }, { responseType: 'arraybuffer' }).then(response => {
const blob = new Blob([response.data], { type: 'application/octet-stream' })
saveAs(blob, 'example.zip')
})
In this code, we're setting the responseType option to 'arraybuffer' so that the response data is returned as an ArrayBuffer object, which we can then use to create a new Blob object. We're passing this Blob object and the desired filename to the saveAs function to trigger the download.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论