簡體   English   中英

Axios 不斷下載損壞的 PDF

[英]Axios keeps downloading a corrupted PDF

當我使用 axios 將 PDF 文件下載到客戶端時,它總是以損壞告終。 我有一個 MERN 堆棧網絡應用程序,它允許用戶單擊按鈕下載 PDF 文件。 單擊按鈕會向 Node.js Web 服務器發送 axios GET 請求。 我正在使用 express.js 來處理路由和請求。 快速路由將使用 Google API 將 Google Doc 作為 PDF 下載到 Node.js 服務器,然后我希望 Node.js 將該 PDF 發送到客戶端的瀏覽器。 一切正常,除了下載總是在客戶端損壞。 (pdf 下載並完美打開到 Node.js)

這是當用戶單擊按鈕時發送到 Node.js 的 Axios get 請求。 (我使用 react-redux 作為調度函數)。 我曾嘗試將 responseType 設置為“blob”,但不起作用。

export const downloadDocument = (googleDocId) => (dispatch) => {
  dispatch({
    type: DOCUMENT_DOWNLOADING
  })
  axios.get('/api/documents/download?googleDocId=' + googleDocId, {
      responseType: 'arraybuffer'
    })
    .then(res => {
      dispatch({
        type: DOCUMENT_DOWNLOADED,
        payload: res.data
      })
      const url = window.URL.createObjectURL(new Blob([res.data]), {
        type: 'application/pdf'
      })
      const link = document.createElement('a')
      link.href = url;
      link.setAttribute('download', 'LOR.pdf')
      document.body.appendChild(link)
      link.click()
    })
    .catch(err => {
      dispatch(returnErrors(err.response.data, err.response.status))
      dispatch({
        type: DOCUMENT_DOWNLOAD_FAIL
      })
    })
}

這是處理下載請求的后端 express.js 代碼:

erouter.get('/download', async (req, res) => {
  const googleDocId = req.query.googleDocId
  if (!googleDocId) {
    return res.status(400).json({
      msg: "googleDocId not specified"
    })
  }

  //Use the Google API to download a PDF from Google Drive
  const { google } = require("googleapis")
  const fs = require('fs')

  const auth = new google.auth.GoogleAuth({
    keyFile: "credentials.json",
    scopes: ["https://www.googleapis.com/auth/drive"]
  })

  //Create client instance for auth
  const client = await auth.getClient()

  // Instance of Google Drive API
  const gDrive = google.drive({
    version: "v3",
    auth: client
  })

  //Download file as PDF from google Drive to node.js server
  await gDrive.files.export({
    fileId: googleDocId,
    mimeType: 'application/pdf'
  }, {
    responseType: 'stream'
  })
    .then(response => {
      return new Promise((resolve, reject) => {
        const filePath = path.join(__dirname, "../../tmp")
        console.log(`writing to ${filePath}`);
        const dest = fs.createWriteStream(filePath);
        let progress = 0

        response.data
          .on('end', () => {
            console.log('Done downloading file.')
            resolve(filePath)
          })
          .on('error', err => {
            console.error('Error downloading file.')
            reject(err)
          })
          .on('data', d => {
            progress += d.length;
            if (process.stdout.isTTY) {
              process.stdout.clearLine()
              process.stdout.cursorTo(0)
              process.stdout.write(`Downloaded ${progress} bytes`)
            }
          })
          .pipe(dest)
      })
    })
    .catch(err => console.log(err))

    //Download file to client browser
    const options = {
        root: path.join(__dirname, "../../tmp"),
        headers: {
            'Content-Type' : 'application/pdf'
        }
    }
    var filename = "LOR.pdf"
    res.sendFile(filename, options)
    //res.download('./tmp/LOR.pdf')
})

可能出什么問題了? 在使用 responseType: 'arraybuffer' 之后的某個時候,按照其他在線 axios 線程的推薦,下載確實有效並下載了一次有效的 PDF,但是效果不一致並且幾乎總是導致客戶端瀏覽器上的 PDF 損壞。 有人請幫助我快瘋了。 我曾嘗試使用 download.js npm 包,但這並沒有給我想要的結果。 我也嘗試過這些線程的建議: https : //gist.github.com/javilobo8/097c30a233786be52070986d8cdb1743 https://github.com/axios/axios/issues/448 <-第二個鏈接中的這個解決方案工作一次,然后后來不斷導致損壞的PDF下載

我讓它完全按照我的意圖工作! 謝謝菲爾的指導。 Google API 流式傳輸 PDF,將管道連接到 express res 對象,並將 PDF 直接流式傳輸到 res,我可以將其重建為另一側的 blob。 它現在可以工作,根本不需要將 PDF 寫入 node.js 服務器!

//Stream file as PDF from google Drive and pipe it to express res 
gDrive.files.export({fileId: googleDocId, mimeType: 'application/pdf'}, {responseType: 'stream'})
    .then(response => {
        return new Promise((resolve, reject) => {
            console.log('Beginning download stream')
            let progress = 0
            response.data
                .on('end', () => {
                    console.log('Done downloading file.')
                    resolve()
                })
                .on('error', err => {
                    console.error('Error downloading file.')
                    reject(err)
                })
                .on('data', d => {
                    progress += d.length;
                    if (process.stdout.isTTY) {
                        process.stdout.clearLine()
                        process.stdout.cursorTo(0)
                        process.stdout.write(`Downloaded ${progress} bytes`)
                    }
                })
                .pipe(res) //Pipe data to the express res object
        })
    })
    .catch(err => console.log(err))

試試這個,它應該工作

// Your code 
const url =  window.URL.createObjectURL(new File([new Blob([res.data])], "LOR.pdf", {type: 'application/pdf'}))
// Your code

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM