简体   繁体   English

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

[英]How can I download a file using window.fetch?

If I want to download a file, what should I do in the then block below?如果我想下载一个文件,我应该在下面的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(...);
}

Note the codes are in client-side.请注意,代码在客户端。

EDIT : syg answer is better.编辑:syg 答案更好。 Just use downloadjs library.只需使用downloadjs库。

The answer I provided works well on Chrome, but on Firefox and IE you need some different variant of this code.我提供的答案在 Chrome 上运行良好,但在 Firefox 和 IE 上,您需要此代码的一些不同变体。 It's better to use library for that.最好为此使用库。


I had similar problem (need to pass authorization header to download a file so this solution didn't helped).我有类似的问题(需要通过授权标头来下载文件,所以这个解决方案没有帮助)。

But based on this answer you can use createObjectURL to make browser save a file downloaded by Fetch API.但是基于答案,您可以使用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         
        });
    });

This is more shorter and efficient, no libraries only fetch API这更短更高效,没有库只获取 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); });

I temporarily solve this problem by using download.js and blob .我通过使用download.jsblob暂时解决了这个问题。

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

It's working for small files, but maybe not working for large files.它适用于小文件,但可能不适用于大文件。 I think I should dig Stream more.我想我应该更多地挖掘Stream

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

or:要么:

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

Using dowloadjs.使用下载js。 This will parse the filename from the header.这将从标题中解析文件名。

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

Here is an example using node-fetch for anyone that finds this.这是一个使用 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)
}

I tried window.fetch but that ended up being complicated with my REACT app我试过 window.fetch 但结果我的 REACT 应用程序变得很复杂

now i just change window.location.href and add query params like the jsonwebtoken and other stuff .现在我只需更改 window.location.href 并添加查询参数,例如jsonwebtokenother stuff


///==== client side code =====
var url = new URL(`http://${process.env.REACT_APP_URL}/api/mix-sheets/list`);
url.searchParams.append("interval",data.interval);
url.searchParams.append("jwt",token)

window.location.href=url;

// ===== server side code =====

// on the server i set the content disposition to a file
var list = encodeToCsv(dataToEncode);
res.set({"Content-Disposition":`attachment; filename=\"FileName.csv\"`});
res.status(200).send(list)

the end results actually end up being pretty nice, the window makes request and downloads the file and doesn't event switch move the page away, its as if the window.location.href call was like a lowkey fetch() call.最终结果实际上非常好,窗口发出请求并下载文件并且不会事件切换将页面移开,就好像window.location.href调用就像一个低调的fetch()调用一样。

As per some of the other answers, you can definitely use window.fetch and download.js to download a file.根据其他一些答案,您绝对可以使用 window.fetch 和download.js下载文件。 However, using window.fetch with blob has the restriction on memory imposed by the browser, and the download.js also has its compatibility restrictions .但是,使用window.fetch 和blob 有浏览器对内存的限制,而download.js 也有其兼容性限制

If you need to download a big-sized file, you don't want to put it in the memory of the client side to stress the browser, right?如果你需要下载一个大文件,你不想把它放在客户端的内存中给浏览器带来压力,对吧? Instead, you probably prefer to download it via a stream.相反,您可能更喜欢通过流下载它。 In such a case, using an HTML link to download a file is one of the best/simplest ways, especially for downloading big-sized files via a stream.在这种情况下,使用 HTML 链接下载文件是最好/最简单的方法之一,尤其是通过流下载大文件。

Step One: create and style a link element第一步:创建链接元素并为其设置样式

You can make the link invisible but still actionable.您可以使链接不可见,但仍可操作。

HTML: HTML:

<a href="#" class="download-link" download>Download</a>

CSS: CSS:

.download-link {
  position: absolute;
  top: -9999px;
  left: -9999px;
  opacity: 0;
}

Step Two: Set the href of the link, and trigger the click event第二步:设置链接的href ,触发click事件

JavaScript 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()

Notes :注意事项

  • You can dynamically generate the link element if necessary.如有必要,您可以动态生成链接元素。
  • This approach is especially useful for downloading, via a stream, big-sized files that are dynamically generated on the server side这种方法对于通过流下载在服务器端动态生成的大文件特别有用

A similar but cleaner and more reliable solution IMO.类似但更清洁、更可靠的解决方案 IMO。

On your fetch function...在您的提取功能上...

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

and the downloadFile function is...而 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);
}

(downloadFile function source: https://gist.github.com/davalapar/d0a5ba7cce4bc599f54800da22926da2 ) (下载文件函数源码: https : //gist.github.com/davalapar/d0a5ba7cce4bc599f54800da22926da2

No libraries only fetch API.没有库只获取 API。 Also you can change the file name您也可以更改文件名

function myFetch(textParam, typeParam) {
  fetch("http://localhost:8000/api", {
    method: "POST",
    headers: {
      Accept: "application/json, text/plain, */*",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      text: textParam,
      barcode_type_selection: typeParam,
    }),
  })
    .then((response) => {
      return response.blob();
    })
    .then((blob) => {
      downloadFile(blob);
    });
}

Here is the download file function这是下载文件function

function downloadFile(blob, name = "file.pdf") {
  const href = URL.createObjectURL(blob);
  const a = Object.assign(document.createElement("a"), {
    href,
    style: "display:none",
    download: name,
  });
  document.body.appendChild(a);
  a.click();
  URL.revokeObjectURL(href);
  a.remove();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM