无法使用React JS从Mongo-db下载以二进制数据格式存储的PDF文件。

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

Not able to download pdf-file (stored in binary data format) from Mongo-db using React JS

问题

I used express-fileupload to upload the PDF file to MongoDB. I am encountering a problem when trying to download that PDF file on the front end.

I'm receiving this error prompt after downloading the PDF: "Error. Failed to load PDF document".

FormData on MongoDB:

_id: ObjectId('63b7494295b850d0452a6a81')
username: "sita"
email: "sita@gmail.com"
dob: 2023-01-01T00:00:00.000+00:00
city: "city"
address: "add"
services: Array
0: "Demat"
pancard: Object
    Data: BinData(0,'JVBERi0xLjcKCjQgMCBvYmoKPDwKL0ZpbHRlciAvRmxhdGVEZWNvZGUKL0xlbmd0aCAzMDEzNQo+PgpzdHJlYW0KeJztvU1247gS…')
    ContentType: "application/pdf"
createdAt: 2023-01-05T22:03:46.893+00:00
updatedAt: 2023-01-05T22:03:46.893+00:00
__v: 0

[ReactJS code:]

React.useEffect(() => {
    const fetchClient = async () => {
        const res = await axios.get('/users/sita@gmail.com');
        setData(res.data.pancard.Data.data);
        setContentType(res.data.pancard.contentType);
    }

    fetchClient();
}, [userdetail]);

const downloadPdf = (filename, contentType) => {
    const file = new Blob([data], { type: contentType });
    saveAs(file, "pancard.pdf");
    // const fileURL = URL.createObjectURL(file);
    // window.open(fileURL);
};

Calling downloadPdf() method here in JSX:

<button class="btn btn-primary button" onClick={downloadPdf('pancard', contentType)}>Download</button>

The file is also getting downloaded infinitely in a loop.

Image Link

英文:

I used express-fileuplod for uploading the pdf file on Mongodb. I am facing problem to download that pdf file on front end.

I'm getting this prompt after downloading the pdf: "Error. Failed to load PDF document"

form-data on MongoDB:

_id: ObjectId(&#39;63b7494295b850d0452a6a81&#39;)                                     
username: &quot;sita&quot;                                                                 
email: &quot;sita@gmail.com&quot;                                                            
dob: 2023-01-01T00:00:00.000+00:00                                                
city: &quot;city&quot;                                                                  
address: &quot;add&quot;                                                                   
services: Array                                                                     
0: &quot;Demat&quot;                                                                            
pancard: Object                                                                 
    Data:BinData(0,&#39;JVBERi0xLjcKCjQgMCBvYmoKPDwKL0ZpbHRlciAvRmxhdGVEZWNvZGUKL0xlbmd0aCAzMDEzNQo+PgpzdHJlYW0KeJztvU1247gS…&#39;)                                                
    ContentType: &quot;application/pdf&quot;                                                   
createdAt: 2023-01-05T22:03:46.893+00:00                                       
updatedAt: 2023-01-05T22:03:46.893+00:00                                             
__v: 0  

[reactjs code:]

React.useEffect(()=&gt;{
    const fetchClient = async () =&gt;{
        const res = await axios.get(&#39;/users/sita@gmail.com&#39;);
        setData(res.data.pancard.Data.data);
        setContentType(res.data.pancard.contentType)
    }

   fetchClient()       
},[userdetail]);


const downloadPdf = (filename, contentType) =&gt; {
      const file = new Blob([data], { type: contentType });
      saveAs(file, &quot;pancard.pdf&quot;) 
      //const fileURL = URL.createObjectURL(file);
      //window.open(fileURL);       
  };

Calling downloadpdf() method here in JSX

> <button class="btn btn-primary button" onClick={downloadPdf('pancard', contentType)}>Download</button>

The file is also getting downloaded infinite times in loop

答案1

得分: 1

Solution 1

那个 data 只是一个数组,我们需要将其转换为 Uint8Array

const file = new Blob([new Uint8Array(data)], { type: contentType });
saveAs(file, "pancard.pdf") 

Solution 2

我们必须在另一个路由上提供文件,不能与 JSON 数据一起发送

后端

// 在 Express 中的示例
app.get('/get_file', (req, res) => {
  // 查询用户
  res.set('Content-Disposition', 'attachment; filename="test.pdf"');
  res.set('Content-Type', 'application/pdf');
  res.send(user.pancard);
}

前端

fetch('http://localhost:8000/get_file')
      .then(res => res.blob())
      .then(data => {
        saveAs(data, 'test.pdf');
      })

对于大文件,Solution 2 更好,因为它使用了 Content-Disposition 标头,可以安全地传输文件数据(我不太了解其底层机制,请进一步研究)


还请注意两件事情:

  • 不建议将文件数据直接保存到数据库中。而是将其保存为静态文件,只将路径存储到数据库中。
  • 如果文件大小超过 16mb,则需要使用 Mongo 的 GridFS。更多详情:https://www.mongodb.com/docs/manual/core/gridfs/
英文:

Solution 1

That data is only an Array, we need to convert to Uint8Array

const file = new Blob([new Uint8Array(data)], { type: contentType });
saveAs(file, &quot;pancard.pdf&quot;) 

Solution 2

We have to serve file on another route, it can not be sent with json data

backend

// Example in Express
app.get(&#39;/get_file&#39;, (req, res) =&gt; {
  // Query user
  res.set(&#39;Content-Disposition&#39;, &#39;attachment; filename=&quot;test.pdf&quot;&#39;);
  res.set(&#39;Content-Type&#39;, &#39;application/pdf&#39;);
  res.send(user.pancard);
}

frontend

fetch(&#39;http://localhost:8000/get_file&#39;)
      .then(res =&gt; res.blob())
      .then(data =&gt; {
        saveAs(data, &#39;test.pdf&#39;);
      })

With large file, Solution 2 is better thanks to the Content-Disposition header. File data is transferred safely with this header (I don't really understand the underlying mechanism, please research further)


Also notice 2 things:

  • It is not recommend to save file data directly into database. Instead, save as static file and only store the path to database.
  • If file size exceed 16mb. We need to use GridFS for Mongo. More details: https://www.mongodb.com/docs/manual/core/gridfs/

huangapple
  • 本文由 发表于 2023年1月7日 07:00:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/75036873.html
匿名

发表评论

匿名网友

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

确定