Downloading ZIP file using NodeJS and ReactJS

huangapple go评论129阅读模式
英文:

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 : &quot;null&quot;, ctx.request.url())
        const { docs } = ctx.request.all()
        const rdocs = !!docs &amp;&amp; docs.length &gt; 0 ? docs : []
        //Recupera os pdfs do banco de dados e salva um zip no /tmp
        if(rdocs.length &gt; 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 = &quot;/tmp/&quot;+rdocs[x]+&quot;.pdf&quot;
                     zip.addFile(rdocs[x]+&quot;.pdf&quot;,file.binario)
                 }
             }
             var data = zip.toBuffer()
             var fileName = &quot;flavio.zip&quot;
             zip.writeZip(&quot;/tmp/&quot;+fileName)
             ctx.response.header(&#39;Content-Type&#39;, &#39;application/octet-stream&#39;)
             ctx.response.header(&#39;Content-Disposition&#39;, `attachment; filename=${fileName}`)
             ctx.response.header(&#39;Content-Length&#39;, data.length)
             ctx.response.send(data);
        }
        else {
            ctx.response.status(404).send()
        }
        return { status: &#39;ok&#39; }
    }
 }

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(&#39;/mediateca/downloadzipfile&#39;, { docs: dcs }, { responseType: &#39;arraybuffer&#39; }).then(response =&gt; {
    const blob = new Blob([response.data], { type: &#39;application/octet-stream&#39; })
    saveAs(blob, &#39;example.zip&#39;)
})

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.

huangapple
  • 本文由 发表于 2023年5月14日 22:46:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/76248073.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定