Res.download() 使用 html 表单提交但不是 Axios 发布调用 [英] Res.download() working with html form submit but not an Axios post call

查看:34
本文介绍了Res.download() 使用 html 表单提交但不是 Axios 发布调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个小应用程序,该应用程序将来自 React 应用程序的信息提交到 Express 服务器的/download"API,然后它将新文件写入本地文件系统并使用 Express 在客户端下载新创建的文件fs.writeFile() 回调中的 res.download().

我一直在使用常规的 html 表单提交来发布数据,但由于复杂性的增加,我已经使用 Axios 进行了切换,但它不再起作用.

奇怪的是只有客户端的下载似乎停止了.编写文件工作正常,所有控制台日志都是相同的(文件已下载!"下面的日志).当我切换回表单提交时,它继续工作,所以唯一的变化是使用 Axios 发送发布请求.据我所知,一旦数据到达那里,两者之间应该没有任何区别,但我希望有人比我更了解这一点.

除了在表单和 Axios 发布请求之间进行测试之外,我还尝试将 Axios 请求的内容类型从application/json"更改为x-www-form-urlencoded",认为匹配内容输入表单发送的内容可能是答案

以下是相关应用的相关代码片段:

server.js(节点 JS)

app.post('/download', (req, res) => {console.log("请求数据");控制台日志(req.body.html);fs.writeFile("./dist/test.txt", res.body.test,(错误) =>{如果(错误){返回 console.log(err);} 别的{console.log("文件已保存!");}让文件 = __dirname + '/text.txt';/*这是问题,文件没有为下面的Axios迭代下载客户端*/res.download(文件,(错误)=>{如果(错误){控制台日志(错误);} 别的 {控制台日志(文件);/*以下两个View.js迭代的日志*/console.log("文件已下载!");}});});})

App.js(反应)

handleSubmit(e){e.preventDefault();axios.post(`/download`, {test: "test"}).then(res => {console.log("请求发送");}).catch((错误) => {控制台日志(错误);});}使成为(){返回(<div><查看handleSubmit={this.handleSubmit}/>

)}

View.js (React)

这有效:

render(){返回(<form action="/download" method="post"><输入类型=提交"></表单>)}

不会在客户端启动下载,但其他方面工作正常:

render(){返回(<form onSubmit={this.props.handleSubmit}><输入类型=提交"></表单>)}

我没有收到任何错误,除了客户端下载之外,一切似乎都正常工作.

预期的结果是使用 Axios 在客户端下载文件,但事实并非如此.

更新:Bump,对此没有任何吸引力

解决方案

实际上,你可以在 Ajax POST 请求中下载文件,加上一些 blob 操作.下面列出了示例代码,并附有说明注释:

handleSubmit(e){var req = new XMLHttpRequest();req.open('POST', '/download', true);//打开一个异步 AJAX 请求.req.setRequestHeader('Content-Type', 'application/json');//由于有问题的 {test: "test"} 发送 JSONreq.responseType = 'blob';//将预期数据定义为 blobreq.onreadystatechange = 函数 () {如果(req.readyState === 4){if (req.status === 200) {//当数据接收成功var data = req.response;var defaultFilename = 'default.pdf';//或者,您可以通过 req.getResponseHeader('Content-Disposition') 从后端获取文件名if (typeof window.navigator.msSaveBlob === '函数') {//如果是支持直接下载blob的IE.window.navigator.msSaveBlob(数据,默认文件名);} 别的 {var blob = 数据;var link = document.createElement('a');link.href = window.URL.createObjectURL(blob);link.download = defaultFilename;document.body.appendChild(link);链接.点击();//创建一个 <a>元素并模拟点击操作.}}}};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(功能(资源){...var data = new Blob([res.data]);if (typeof window.navigator.msSaveBlob === '函数') {//如果是支持直接下载blob的IE.window.navigator.msSaveBlob(数据,默认文件名);} 别的 {var blob = 数据;var link = document.createElement('a');link.href = window.URL.createObjectURL(blob);link.download = defaultFilename;document.body.appendChild(link);链接.点击();//创建一个 <a>元素并模拟点击操作.}}).catch((错误) => {控制台日志(错误);});

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 downloads the newly created file on the client side using the Express res.download() in the fs.writeFile() callback.

I've been using a regular html form submit to post the data but due to an increase in complexity I've switched over using Axios and it's no longer working.

The strange thing is only the download on the client side seems to have stopped working. Writing the file works just fine, all the console logging is the same ("File downloaded!" logs below). When I switch back to the form submit it continues to work so the only change is using Axios to send the post request. As far as I'm aware there shouldn't be any difference between the two once the data gets there but I'm hoping someone has greater insight into this than I.

In addition to testing between form and Axios post requests I've also tried changing the content-type of the Axios request to be "x-www-form-urlencoded" from "application/json" thinking that matching up the content type to what the form was sending might be the answer

The below is the relevant code snippets from the app in question:

server.js (Node 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)

This works:

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

This doesn't initiate the download on the client side, but otherwise works just fine:

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

I'm not getting any error, everything seems to be working properly except the download on the client side.

The expected result is that the file downloads on the client side using Axios but that's not the case.

Update: Bump, not getting any traction on this

解决方案

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

这篇关于Res.download() 使用 html 表单提交但不是 Axios 发布调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆