Res.download() working with html form submit but not an Axios post call

后端 未结 2 1669
时光说笑
时光说笑 2021-01-07 10:55

I am writing a small app that submits information from a React app to an Express server\'s \"/download\" API where it then writes a new file to the local file system and dow

相关标签:
2条回答
  • 2021-01-07 11:11

    The browser won't handle the response of a POST request as a file download, so you either need to make another request or handle the response differently.

    Below is an example of making another request, to go fetch the file after it's been created on the back-end. The other answer gives a nice example of using the Blob API to process the response data directly from the POST request.

     axios.post(`/download`, {test: "test"})
      .then(res => {
        console.log("REQUEST SENT");
    
        // Send back an identifier, or whatever so that you can then
        // retrieve the file with another request. 
    
        // res.id is hypothetical, you simply need to be able to access the file
        // whether by filename, id, however you want.
        window.open("/download?id=" + res.id);
      })
      .catch((error) => {
        console.log(error);
      });
    
    0 讨论(0)
  • 2021-01-07 11:23

    Actually, you CAN download file in Ajax POST request, with some blob operation. Example code is listed below, with explanation comment:

    handleSubmit(e){
      var req = new XMLHttpRequest();
      req.open('POST', '/download', true); // Open an async AJAX request.
      req.setRequestHeader('Content-Type', 'application/json'); // Send JSON due to the {test: "test"} in question
      req.responseType = 'blob'; // Define the expected data as blob
      req.onreadystatechange = function () {
        if (req.readyState === 4) {
          if (req.status === 200) { // When data is received successfully
            var data = req.response;
            var defaultFilename = 'default.pdf';
            // Or, you can get filename sent from backend through req.getResponseHeader('Content-Disposition')
            if (typeof window.navigator.msSaveBlob === 'function') {
              // If it is IE that support download blob directly.
              window.navigator.msSaveBlob(data, defaultFilename);
            } else {
              var blob = data;
              var link = document.createElement('a');
              link.href = window.URL.createObjectURL(blob);
              link.download = defaultFilename;
    
              document.body.appendChild(link);
    
              link.click(); // create an <a> element and simulate the click operation.
            }
          }
        }
      };
      req.send(JSON.stringify({test: 'test'}));
    }
    

    For backend, there is nothing special, just a plain res.download statement:

    app.post('/download', function(req, res) {
      res.download('./example.pdf');
    });
    

    For axios, the frontend code would look like:

    axios.post(`/download`, {test: "test"}, {responseType: 'blob'})
      .then(function(res) {
            ...
            var data = new Blob([res.data]);
            if (typeof window.navigator.msSaveBlob === 'function') {
              // If it is IE that support download blob directly.
              window.navigator.msSaveBlob(data, defaultFilename);
            } else {
              var blob = data;
              var link = document.createElement('a');
              link.href = window.URL.createObjectURL(blob);
              link.download = defaultFilename;
    
              document.body.appendChild(link);
    
              link.click(); // create an <a> element and simulate the click operation.
            }
      })
      .catch((error) => {
        console.log(error);
      });
    
    0 讨论(0)
提交回复
热议问题