Res.download () работает с отправкой html-формы, но не с почтовым вызовом Axios - PullRequest
0 голосов
/ 18 июня 2019

Я пишу небольшое приложение, которое отправляет информацию из приложения React в API-интерфейс сервера «/ download» сервера Express, где оно затем записывает новый файл в локальную файловую систему и загружает вновь созданный файл на стороне клиента с помощью Express res.download () в обратном вызове fs.writeFile ().

Я использовал регулярную отправку html-формы для публикации данных, но из-за увеличения сложности я переключился с помощью Axios, и он больше не работает.

Странно то, что только загрузка на стороне клиента перестала работать. Запись файла работает просто отлично, все журналы консоли одинаковы (журналы «Файл загружен!» Ниже). Когда я возвращаюсь к отправке формы, она продолжает работать, поэтому единственное изменение - использование Axios для отправки запроса на публикацию. Насколько я знаю, между этими двумя данными не должно быть никакой разницы, как только данные туда попадут, но я надеюсь, что кто-то лучше понимает это, чем я.

В дополнение к тестированию между формой и почтовыми запросами Axios, я также попытался изменить тип содержимого запроса Axios на «x-www-form-urlencoded» с «application / json», полагая, что он соответствует контенту. тип того, что отправляла форма, может быть ответом

Ниже приведены соответствующие фрагменты кода из рассматриваемого приложения:

server.js (узел JS)

app.post('/download', (req, res) => {
  console.log("Requst data");
  console.log(req.body.html);


  fs.writeFile("./dist/test.txt", res.body.test,
    (err) => {
      if(err) {
        return console.log(err);
      } else{
        console.log("The file was saved!");
      }

      let file = __dirname + '/text.txt';
      /*This is the issue, the file is not downloading client side for the Axios iteration below*/
      res.download(file,(err)=>{
        if(err){
          console.log(err);
        } else {
          console.log(file);
          /*This logs for both View.js iterations below*/
          console.log("File downloaded!");
        }
      });
    });
})

App.js (React)

handleSubmit(e){
    e.preventDefault();

    axios.post(`/download`, {test: "test"})
      .then(res => {
        console.log("REQUEST SENT");
      })
      .catch((error) => {
        console.log(error);
      });
}

render(){
      return(
        <div>
          <View handleSubmit={this.handleSubmit} />
        </div>
      )
}

View.js (React)

Это работает:

render(){
      return(
        <form action="/download" method="post">
            <input type="submit">
        </form>
      )
}

Этот не инициирует загрузку на стороне клиента, но в остальном работает просто отлично:

render(){
      return(
        <form onSubmit={this.props.handleSubmit}>
            <input type="submit">
        </form>
      )
}

Я не получаю никакой ошибки, кажется, что все работает правильно, за исключением загрузки на стороне клиента.

Ожидаемый результат заключается в том, что файл загружается на стороне клиента с использованием Axios, но это не так.

Обновление: удар, не получая тяги на этом

Ответы [ 2 ]

1 голос
/ 19 июня 2019

На самом деле, вы МОЖЕТЕ загрузить файл в Ajax POST-запросе с помощью некоторой операции BLOB-объекта Пример кода приведен ниже с пояснительным комментарием:

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'}));
}

Для бэкенда нет ничего особенного, просто простое выражение res.download:

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

Для axios код внешнего интерфейса будет выглядеть так:

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);
  });
1 голос
/ 19 июня 2019

Браузер не будет обрабатывать ответ на запрос POST при загрузке файла, поэтому вам нужно либо сделать еще один запрос, либо обработать ответ по-другому.

Ниже приведен пример создания другого запроса для извлечения файла после того, как он был создан на серверной части. Другой ответ дает хороший пример использования API Blob для обработки данных ответа непосредственно из запроса POST.

 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);
  });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...