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


当前回答

对于那些想要实现经过身份验证的本地下载的人。

我目前正在使用Axios开发一个SPA。 不幸的是,Axios在这种情况下不允许流响应类型。 从文档:

// `responseType` indicates the type of data that the server will respond with
// options are: 'arraybuffer', 'document', 'json', 'text', 'stream'
// browser only: 'blob'

但我想出了一个解决办法,就像在这个话题中提到的那样。 诀窍是发送一个包含令牌和目标文件的基本Form POST。

这是针对一个新的窗口。一旦浏览器读取服务器响应上的附件标头,它将关闭新选项卡并开始下载。”

下面是一个例子:

let form = document.createElement('form');
form.method = 'post';
form.target = '_blank';

form.action = `${API_URL}/${targetedResource}`;
form.innerHTML = `'<input type="hidden" name="jwtToken" value="${jwtToken}">'`;

document.body.appendChild(form);
form.submit();
document.body.removeChild(form);

“您可能需要将处理程序标记为未验证/匿名,以便手动验证JWT以确保适当的授权。”

结果是我的ASP。NET实现:

[AllowAnonymous]
[HttpPost("{targetedResource}")]
public async Task<IActionResult> GetFile(string targetedResource, [FromForm] string jwtToken)
{
    var jsonWebTokenHandler = new JsonWebTokenHandler();

    var validationParameters = new TokenValidationParameters()
    {
        // Your token validation parameters here
    };

    var tokenValidationResult = jsonWebTokenHandler.ValidateToken(jwtToken, validationParameters);

    if (!tokenValidationResult.IsValid)
    {
        return Unauthorized();
    }

    // Your file upload implementation here
}

其他回答

Axios。后解决方案与IE和其他浏览器

我在这里找到了一些不可思议的解决方案。但他们通常不会考虑IE浏览器的问题。也许这样可以为别人节省一些时间。

axios.post("/yourUrl",
    data,
    { responseType: 'blob' }
).then(function (response) {
    let fileName = response.headers["content-disposition"].split("filename=")[1];
    if (window.navigator && window.navigator.msSaveOrOpenBlob) { // IE variant
        window.navigator.msSaveOrOpenBlob(new Blob([response.data],
                { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }
            ),
            fileName
        );
    } else {
        const url = window.URL.createObjectURL(new Blob([response.data],
            { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }));
        const link = document.createElement('a');
        link.href = url;
        link.setAttribute('download',
            response.headers["content-disposition"].split("filename=")[1]);
        document.body.appendChild(link);
        link.click();
    }
    }
);

上面的例子适用于excel文件,但是稍加改变就可以应用于任何格式。

在服务器上,我这样做是为了发送一个excel文件。

response.contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"

response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=exceptions.xlsx")
        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 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的文件作为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 const axiosResponse = await axios.get(pdf.url)传输到谷歌驱动器googleDrive.files。create({media: {body: axiosResponse.)data, mimeType}, requestBody: {name: fileName, parents: [parentFolder], mimeType}, auth: jwtClient})上传一个损坏的文件。

文件损坏的原因是axios转换了axiosResponse。数据转换为字符串。为了解决这个问题,我必须要求axios返回一个axios.get流。url, {responseType: 'stream'})。