【问题标题】:How to trigger a browser download from a browser FETCH?如何从浏览器 FETCH 触发浏览器下载?
【发布时间】:2020-03-10 10:48:53
【问题描述】:

我正在开发一个项目,其中 Vue.jsTypescript 作为前端,Java Spring 作为后端。

我的 java 控制器从数据库中检索给定的报告,然后将其复制到 HTML 响应中。 我希望浏览器下载 CSV,因此我在响应中添加了 Content-disposition 标头。

     @GetMapping('/download')
     public void downloadCSV(HttpServletRequest response){
        Report r = reportService.findById(85);
        response.addHeader("Content-Disposition", "attachment; filename=myCSV.csv");
        response.setContentType("text/csv");

        try {
            InputStream stream = new ByteArrayInputStream(r.getDocument());
            IOUtils.copy(stream, response.getOutputStream());
            response.flushBuffer();
        } catch(Exception e) {...}
     }

我有 2 个按钮:一个带有 href 链接到 download() 的简单超链接标签,以及一个一旦点击就会触发 download2() 的 b 按钮(来自 bootstrap-vue) em>。

   <a :href="download" role="button"> Download CSV </a>

   <b-button @click="event => download2()">
      Download CSV v2
   </b-button>
    get download(): string {
        return 'http://localhost:8080/download';
    }


    async download2() {
        const rHeaders = new Headers();
        rHeaders.append('Accept', 'text/csv');

        const configInit = RequestInit = {
           method: 'GET',
           headers: rHeaders
        };

        try {
            const res = await fetch('http://localhost:8080/download', configInit);
            return res.text();
        } catch (e) {...}
    }

现在,如果我点击第一个按钮“下载 csv”,浏览器会正确下载 csv。 javascript 控制台打印以下内容:

Resource interpreted as Document but transferred with MIME type text/csv

响应正文中没有任何内容。

相反,如果我点击第二个按钮“下载 csv v2”,下载不会开始,但响应正文中有 csv。

这里是两者请求头的区别。

*Header*                   *Download csv*        *Download csv v2*
Sec-Fetch-Dest                document               empty
Sec-Fetch-Mode                navigate               cors
Sec-Fetch-User                   ?1                    -
Upgrade-Insecure-Requests        1                     -

其他标题相同。无法更改这些标头,即使我在 javascript 方法中设置它们;它们保持不变。 有什么问题? 谢谢。

【问题讨论】:

  • 只是一个想法:是什么让您认为响应不同?浏览器的行为不同,但毕竟,单击 HTML 超链接与启动异步请求(AJAX 风格)完全是不同的野兽。您是否真的观察到(例如,从浏览器的网络检查器)响应不同?
  • @GPI 你说得对,我说得不好。响应基本相同(所有标题都相同),除了一个(第一个)是“文档”类型,另一个是“获取”类型(来自网络检查器)。浏览器的行为发生变化。我想弄清楚为什么,实际上它们都是 GET 请求。
  • 感谢您的澄清。因此,我建议您完全改写您的问题,
  • 因为您的问题似乎与浏览器相关而不是后端相关。问题不是 spring / java 部分,而是如何从浏览器获取触发浏览器下载
  • 感谢@GPI 的建议,我会改写。

标签: javascript java spring csv fetch-api


【解决方案1】:

我通过“模仿”&lt;a&gt; 元素的行为找到了解决方案:

这样,它就可以正常工作了:

async download2() {
    const configInit: RequestInit = {
        method: 'GET'
    };

    try {
       await fetch('http://localhost:8080/download', configInit)
          .then(response => response.blob())
          .then(blob => {
              const url = window.URL.createObjectURL(blob);
              const a = document.createElement('a');
              a.style.display = 'none';
              a.href = url;
              a.download = 'report.csv';
              document.body.appendChild(a);
              a.click();
              window.URL.revokeObjectURL(url);
          })
    } catch (e) {...}

【讨论】:

    猜你喜欢
    • 2020-04-18
    • 1970-01-01
    • 1970-01-01
    • 2014-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-07
    相关资源
    最近更新 更多