如何使用window.fetch下载文件?

syg*_*syg 37 javascript fetch fetch-api

如果我想下载文件,我应该在then下面的块中做什么?

function downloadFile(token, fileId) {
  let url = `https://www.googleapis.com/drive/v2/files/${fileId}?alt=media`;
  return fetch(url, {
    method: 'GET',
    headers: {
      'Authorization': token
    }
  }).then(...);
}
Run Code Online (Sandbox Code Playgroud)

请注意,代码位于客户端.

Luc*_*tos 77

这更短更高效,没有库只获取 API

const url ='http://sample.example.file.doc'
const authHeader ="Bearer 6Q************" 

const options = {
  headers: {
    Authorization: authHeader
  }
};
 fetch(url, options)
  .then( res => res.blob() )
  .then( blob => {
    var file = window.URL.createObjectURL(blob);
    window.location.assign(file);
  });
Run Code Online (Sandbox Code Playgroud)

  • 有什么办法可以设置文件名吗? (6认同)
  • @luke_16你的建议对我不起作用:有效但没有设置文件名的是 `const fileUrl = window.URL.createObjectURL(blob); window.location.assign(fileUrl)`,但是当我将其修改为`const file = new File([blob], fileName); const fileUrl = window.URL.createObjectURL(file); window.location.assign(fileUrl)`,我让浏览器尝试在不同的网址上显示二进制文件(例如`blob:blob://http://localhost:8070/7174db61-b974-44fb-8a15-946f400378d0`) 。有什么想法有什么问题吗? (6认同)
  • 是的,您可以将 Content-Disposition 添加到 Headers obj,这里是文档 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition (4认同)
  • @LucasMatos我向选项对象添加了“Content-Disposition”标头,并且在网络选项卡中检查文件时我确实获得了正确的标头,但是随后创建了 blob 并且名称被丢弃,因此我最终得到了生成的随机数姓名。您知道如何使用您的解决方案将名称传递给 blob 吗? (2认同)
  • @LucasMatos 我尝试编辑您的答案,但队列已满。为了为正在下载的文件断言名称是添加额外的一行: var file = new File([blob], "filename.extension"); 文件 = window.URL.createObjectURL(file); (2认同)

Mar*_*ski 41

编辑:syg答案更好.只需使用downloadjs库.

我提供的答案在Chrome上运行良好,但在Firefox和IE上你需要一些不同的代码变体.为此使用库更好.


我有类似的问题(需要传递授权标题来下载文件,所以这个解决方案没有帮助).

但基于答案,您可以使用createObjectURL浏览器保存Fetch API下载的文件.

getAuthToken()
    .then(token => {
        fetch("http://example.com/ExportExcel", {
            method: 'GET',
            headers: new Headers({
                "Authorization": "Bearer " + token
            })
        })
        .then(response => response.blob())
        .then(blob => {
            var url = window.URL.createObjectURL(blob);
            var a = document.createElement('a');
            a.href = url;
            a.download = "filename.xlsx";
            document.body.appendChild(a); // we need to append the element to the dom -> otherwise it will not work in firefox
            a.click();    
            a.remove();  //afterwards we remove the element again         
        });
    });
Run Code Online (Sandbox Code Playgroud)

  • 最后调用 URL.revokeObjectURL 以避免内存泄漏是有意义的。 (3认同)
  • 我不同意使用库是更好的答案:)。使用外部库并不总是一种选择,如果是的话,那么找到库就很容易了。这不值得回答,这可能就是为什么你的答案比被接受的答案拥有更多的票数,尽管被接受的答案比被接受的答案早了 2 岁。 (3认同)
  • 另外查看 downloadjs 上的代码,他们使用与 temp <a/> 相同的方法来保存文件。所以图书馆不一定会采取更好的方式。 (2认同)

syg*_*syg 34

我通过使用download.js和暂时解决这个问题blob.

let download = require('./download.min');

...

function downloadFile(token, fileId) {
  let url = `https://www.googleapis.com/drive/v2/files/${fileId}?alt=media`;
  return fetch(url, {
    method: 'GET',
    headers: {
      'Authorization': token
    }
  }).then(function(resp) {
    return resp.blob();
  }).then(function(blob) {
    download(blob);
  });
}
Run Code Online (Sandbox Code Playgroud)

它适用于小文件,但可能不适用于大文件.我想我应该更多地挖掘Stream.

  • 请记住,浏览器的当前blob大小限制约为500mb (7认同)

Zib*_*bri 15

function download(dataurl, filename) {
  var a = document.createElement("a");
  a.href = dataurl;
  a.setAttribute("download", filename);
  a.click();
  return false;
}

download("data:text/html,HelloWorld!", "helloWorld.txt");
Run Code Online (Sandbox Code Playgroud)

或者:

function download(url, filename) {
fetch(url).then(function(t) {
    return t.blob().then((b)=>{
        var a = document.createElement("a");
        a.href = URL.createObjectURL(b);
        a.setAttribute("download", filename);
        a.click();
    }
    );
});
}

download("https://get.geojs.io/v1/ip/geo.json","geoip.json")
download("data:text/html,HelloWorld!", "helloWorld.txt");
Run Code Online (Sandbox Code Playgroud)


Dan*_*iel 8

使用下载js。这将从标题中解析文件名。

fetch("yourURL", {
    method: "POST",
    body: JSON.stringify(search),
    headers: {
        "Content-Type": "application/json; charset=utf-8"
    }
    })
    .then(response => {
        if (response.status === 200) {
            filename = response.headers.get("content-disposition");
            filename = filename.match(/(?<=")(?:\\.|[^"\\])*(?=")/)[0];
            return response.blob();
        } else {
        return;
        }
    })
    .then(body => {
        download(body, filename, "application/octet-stream");
    });
};
Run Code Online (Sandbox Code Playgroud)

  • Firefox 不支持 `filename.match()`,我用以下内容替换了该部分: `filename = response.headers.get("content-disposition").split(";")[1].split('"') [1];` . 此外,服务器必须声明标头 `Access-Control-Expose-Headers: Content-Disposition` 才能允许浏览器读取 `content-disposition` 标头。 (2认同)

Mic*_*bbs 7

这是一个使用 node-fetch 的示例,供任何找到此示例的人使用。

reportRunner({url, params = {}}) {
    let urlWithParams = `${url}?`
    Object.keys(params).forEach((key) => urlWithParams += `&${key}=${params[key]}`)
    return fetch(urlWithParams)
        .then(async res => ({
            filename: res.headers.get('content-disposition').split('filename=')[1],
            blob: await res.blob()
        }))
        .catch(this.handleError)
}
Run Code Online (Sandbox Code Playgroud)


Yuc*_*uci 6

根据其他一些答案,您绝对可以使用 window.fetch 和download.js来下载文件。但是,将 window.fetch 与 blob 一起使用会受到浏览器对内存的限制,并且 download.js 也有其兼容性限制

如果你需要下载一个大文件,你不想把它放在客户端的内存中给浏览器带来压力,对吧?相反,您可能更喜欢通过流下载它。在这种情况下,使用 HTML 链接下载文件是最好/最简单的方法之一,特别是通过流下载大尺寸文件。

第一步:创建链接元素并设置其样式

您可以使链接不可见,但仍可操作。

HTML:

<a href="#" class="download-link" download>Download</a>
Run Code Online (Sandbox Code Playgroud)

CSS:

.download-link {
  position: absolute;
  top: -9999px;
  left: -9999px;
  opacity: 0;
}
Run Code Online (Sandbox Code Playgroud)

第二步:设置href链接的值,并触发click事件

JavaScript

let url = `https://www.googleapis.com/drive/v2/files/${fileId}?alt=media`;

const downloadLink = document.querySelector('.download-link')
downloadLink.href = url + '&ts=' + new Date().getTime() // Prevent cache
downloadLink.click()
Run Code Online (Sandbox Code Playgroud)

注意事项

  • 如果需要,您可以动态生成链接元素。
  • 这种方法对于通过流下载在服务器端动态生成的大尺寸文件特别有用


lem*_*nnk 5

在我看来,这是一个类似但更清洁、更可靠的解决方案。

在你的获取函数上...

fetch(...)    
.then(res => 
    {
        //you may want to add some validation here
        downloadFile(res);
    }
)
Run Code Online (Sandbox Code Playgroud)

downloadFile 函数是...

async function downloadFile(fetchResult) {        
    var filename = fetchResult.headers.get('content-disposition').split('filename=')[1];
    var data = await fetchResult.blob();
    // It is necessary to create a new blob object with mime-type explicitly set
    // otherwise only Chrome works like it should
    const blob = new Blob([data], { type: data.type || 'application/octet-stream' });
    if (typeof window.navigator.msSaveBlob !== 'undefined') {
        // IE doesn't allow using a blob object directly as link href.
        // Workaround for "HTML7007: One or more blob URLs were
        // revoked by closing the blob for which they were created.
        // These URLs will no longer resolve as the data backing
        // the URL has been freed."
        window.navigator.msSaveBlob(blob, filename);
        return;
    }
    // Other browsers
    // Create a link pointing to the ObjectURL containing the blob
    const blobURL = window.URL.createObjectURL(blob);
    const tempLink = document.createElement('a');
    tempLink.style.display = 'none';
    tempLink.href = blobURL;
    tempLink.setAttribute('download', filename);
    // Safari thinks _blank anchor are pop ups. We only want to set _blank
    // target if the browser does not support the HTML5 download attribute.
    // This allows you to download files in desktop safari if pop up blocking
    // is enabled.
    if (typeof tempLink.download === 'undefined') {
        tempLink.setAttribute('target', '_blank');
    }
    document.body.appendChild(tempLink);
    tempLink.click();
    document.body.removeChild(tempLink);
    setTimeout(() => {
        // For Firefox it is necessary to delay revoking the ObjectURL
        window.URL.revokeObjectURL(blobURL);
    }, 100);
}
Run Code Online (Sandbox Code Playgroud)

(downloadFile函数源码:https://gist.github.com/davalapar/d0a5ba7cce4bc599f54800da22926da2