我使用axios的基本http请求,如GET和POST,它工作得很好。现在我需要能够下载Excel文件。这在axios中可行吗?如果是,谁有一些示例代码?如果不是,我还可以在React应用程序中使用什么来做同样的事情?


当前回答

你需要返回File({file_to_download}, "application/vnd.ms-excel")从后端到前端,在你的js文件中,你需要更新下面写的代码:

function exportToExcel() {
        
        axios.post({path to call your controller}, null,
            {
                headers:
                {
                    'Content-Disposition': "attachment; filename=XYZ.xlsx",
                    'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
                },
                responseType: 'arraybuffer',
            }
        ).then((r) => {
            const path= window.URL.createObjectURL(new Blob([r.data]));
            const link = document.createElement('a');
            link.href = path;
            link.setAttribute('download', 'XYZ.xlsx');
            document.body.appendChild(link);
            link.click();
        }).catch((error) => console.log(error));
    }

其他回答

        axios.get(
            '/app/export'
        ).then(response => {    
            const url = window.URL.createObjectURL(new Blob([response]));
            const link = document.createElement('a');
            link.href = url;
            const fileName = `${+ new Date()}.csv`// whatever your file name .
            link.setAttribute('download', fileName);
            document.body.appendChild(link);
            link.click();
            link.remove();// you need to remove that elelment which is created before.
})

下载带有Axios的文件作为responseType: 'blob' 使用Axios/Server响应中的blob创建文件链接 创建<a> HTML元素,使用href链接到步骤2中创建的文件链接,并单击该链接 清理动态创建的文件链接和HTML元素

axios({
    url: 'http://api.dev/file-download', //your url
    method: 'GET',
    responseType: 'blob', // important
}).then((response) => {
    // create file link in browser's memory
    const href = URL.createObjectURL(response.data);

    // create "a" HTML element with href to file & click
    const link = document.createElement('a');
    link.href = href;
    link.setAttribute('download', 'file.pdf'); //or any other extension
    document.body.appendChild(link);
    link.click();

    // clean up "a" element & remove ObjectURL
    document.body.removeChild(link);
    URL.revokeObjectURL(href);
});

在https://gist.github.com/javilobo8/097c30a233786be52070986d8cdb1743上查看这些怪癖

全部演职员表发送至:https://gist.github.com/javilobo8

URL的更多文档。createObjectURL在MDN上可用。释放带有URL的对象非常关键。revokeObjectURL防止内存泄漏。在上面的函数中,因为我们已经下载了文件,所以可以立即撤销对象。

每次调用createObjectURL()时,都会创建一个新的对象URL,即使您已经为同一个对象创建了一个URL。当你不再需要它们时,必须调用URL.revokeObjectURL()来释放它们。

当文档被卸载时,浏览器会自动释放对象url;但是,为了优化性能和内存使用,如果存在可以显式卸载它们的安全时间,则应该这样做。

对于axios POST请求,请求应该是这样的: 这里的关键是responseType和header字段必须在Post的第3个参数中。第二个参数是应用程序参数。

export const requestDownloadReport = (requestParams) => async dispatch => { 
  let response = null;
  try {
    response = await frontEndApi.post('createPdf', {
      requestParams: requestParams,
    },
    {
      responseType: 'arraybuffer', // important...because we need to convert it to a blob. If we don't specify this, response.data will be the raw data. It cannot be converted to blob directly.
      headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/pdf'
      }
  });          
  }
  catch(err) {
    console.log('[requestDownloadReport][ERROR]', err);
    return err
  }

  return response;
}

实现接收文档的Axios处理程序,数据格式为octect-stream, 数据可能看起来很奇怪PK一些JbxfFGvddvbdfbVVH34365436fdkln作为它的八字节流格式,你可能最终会创建这个数据可能被损坏的文件,{responseType: 'blob'}将数据转换为可读格式,

axios.get("URL", {responseType: 'blob'})
     .then((r) => {
         let fileName =  r.headers['content-disposition'].split('filename=')[1];
         let blob = new Blob([r.data]);
         window.saveAs(blob, fileName);             
      }).catch(err => {
        console.log(err);
      });

你可能尝试过这样的解决方案, 窗口。saveAs(blob, 'file.zip')将尝试将文件保存为zip,但将不会工作,

const downloadFile = (fileData) => {
    axios.get(baseUrl+"/file/download/"+fileData.id)
        .then((response) => {
            console.log(response.data);
            const blob = new Blob([response.data], {type: response.headers['content-type'], encoding:'UTF-8'});
            const link = document.createElement('a');
            link.href = window.URL.createObjectURL(blob);
            link.download = 'file.zip';
            link.click();
        })
        .catch((err) => console.log(err))
}
const downloadFile = (fileData) => {
axios.get(baseUrl+"/file/download/"+fileData.id)
    .then((response) => {
        console.log(response);
        //const binaryString = window.atob(response.data)
        //const bytes = new Uint8Array(response.data)
        //const arrBuff = bytes.map((byte, i) => response.data.charCodeAt(i));
        //var base64 = btoa(String.fromCharCode.apply(null, new Uint8Array(response.data)));
        const blob = new Blob([response.data], {type:"application/octet-stream"});
        window.saveAs(blob, 'file.zip')
        // const link = document.createElement('a');
        // link.href = window.URL.createObjectURL(blob);
        // link.download = 'file.zip';
        // link.click();
    })
    .catch((err) => console.log(err))
}
function base64ToArrayBuffer(base64) {
    var binaryString = window.atob(base64);
    var binaryLen = binaryString.length;
    var bytes = new Uint8Array(binaryLen);
    for (var i = 0; i < binaryLen; i++) {
        var ascii = binaryString.charCodeAt(i);
        bytes[i] = ascii;
    };

    return bytes;
}

另一个简单的解决方法是,

window.open("URL")

将继续打开不必要的新选项卡,用户可能不得不让允许弹出的工作这段代码,如果用户想同时下载多个文件,所以先去解决方案或如果不尝试其他解决方案也怎么办

诀窍是在render()中创建一个不可见的锚标记,并添加一个React ref,允许在我们有axios响应时触发单击:

class Example extends Component {
    state = {
        ref: React.createRef()
    }

    exportCSV = () => {
        axios.get(
            '/app/export'
        ).then(response => {
            let blob = new Blob([response.data], {type: 'application/octet-stream'})
            let ref = this.state.ref
            ref.current.href = URL.createObjectURL(blob)
            ref.current.download = 'data.csv'
            ref.current.click()
        })
    }

    render(){
        return(
            <div>
                <a style={{display: 'none'}} href='empty' ref={this.state.ref}>ref</a>
                <button onClick={this.exportCSV}>Export CSV</button>
            </div>
        )
    }
}

以下是文档:https://reactjs.org/docs/refs-and-the-dom.html。你可以在这里找到类似的想法:https://thewebtier.com/snippets/download-files-with-axios/。