9

In the background management system, we often encounter the need for file export. Below, I will give a brief introduction to several common export methods, so that when you encounter such needs in the future, you can be realistic and adopt relative Reasonable way.

Export target

File address
Files that already exist on the server, such as pictures, materials uploaded by users, etc.
http://192.168.1.103:3000/imgs/bg.jpg

Export interface
According to user needs, dynamically generated files, such as export business flow table, data summary table, etc.
http://192.168.1.103:3000/api/export

Export method

image.png

a.download

html5 new attributes

The file name is specified by the front end, and the front end issues a save instruction

Disadvantages: ie does not support, and when cross-domain, even if cross-domain response headers are set in the background, it cannot be downloaded, that is, it must be consistent with the current domain

<a href="http://192.168.1.103:3000/imgs/xx.jpg" download />
<a href="http://192.168.1.103:3000/imgs/xx.jpg" download="xx.jpg" />

ajax + a.download

The file name is specified by the front desk, and the front desk issues a save instruction

Convert the binary data returned in the background into a blob, then use URL.createObjectURL to create a URL pointing to the blob in the memory, and then use the download attribute of the a tag to export

Disadvantages: ie does not support, blobs have memory limitations
image.png

But it avoids the problem that a.download must be consistent with the domain name when used alone

function useLinkDownload(url, fileName) {
    const link = document.createElement("a");

    link.style.display = "none";
    link.href = url;
    link.download = fileName;

    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
}

$.get('http://192.168.1.103:3000/api/export', { responseType: 'blob' })
    .then(function(res) {
        // 创建一个指向内存中blob的URL
        const objectURL = URL.createObjectURL(res.data);
        useLinkDownload(objectURL, 'xx.xlsx')
        URL.revokeObjectURL(objectURL)
    })

ajax + msSaveBlob

The file name is specified by the front desk, and the front desk issues a save instruction

ie proprietary api

Disadvantages: Chrome and firefox do not support, blobs have memory limitations

$.get('http://192.168.1.103:3000/api/export', { responseType: 'blob' })
    .then(function(res) {
        navigator.msSaveBlob(res.data, "xx.xlsx");
    })

content-disposition

The file name is specified by the background, and the priority of the file name specified in this way is higher than that of a.download

The front-end can send the request (others are handed over to the back-end). When the back-end responds to the data, set content-disposition according to the specification. One thing to note is that it cannot be combined with ajax (after using ajax, it will become a binary stream, which requires front-end convection processing)

var url = 'http://192.168.1.103:3000/api/export'

a tag

function useLink(url) {
  const link = document.createElement("a");

  link.style.display = "none";
  link.href = url;

  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
}
useLink(url)

location.href

function useLocationDownload(url) {
  window.location.href = url;
}
useLocationDownload(url)

window.open

function useWindowOpenDownload(url) {
  window.open(url);
}
useWindowOpenDownload(url)

form

function useFormDownload(url) {
  const form = document.createElement("form");

  form.action = url;
  form.method = "get";
  form.style.display = "none";

  document.body.appendChild(form);

  form.submit();
  form.remove();
}
useFormDownload(url)

iframe

function useIframeDownload(url) {
  const iframe = document.createElement("iframe");

  iframe.src = url;
  iframe.style.display = "none";

  document.body.appendChild(iframe);
  document.body.removeChild(iframe);
}
useIframeDownload(url)
  • some problems

    1. Cross-domain

      a.download invalid, even if Access-Control-Allow-Origin is set in the background, it is invalid. The value of download needs to be consistent with the current domain name. Let ngnix forward it.

      https://html.spec.whatwg.org/dev/links.html#downloading-resources

    2. Large file

      The ajax method requires the use of blobs, and there are restrictions on blobs. For example, the upper limit of chrome is 2GB, so the ajax method needs to be excluded. The optional methods are a.download and Content-Disposition. These two methods are not used. blob, so there is no specific limit.

    3. When using a tag or form, in order to avoid page flickering when exporting, we can use target non-_self value to avoid it, but when target is _self, if the export request fails, the page will be overwritten , In which way can I avoid this problem?

      Optional methods are ajax and iframe, both of which can avoid overwriting the current page when it fails, and ajax can also tell the user the reason for the failure

  • to sum up

    By default, when the browser faces files that it cannot open, it will save them locally. However, such as pictures, text files and pdfs, the browser first tries to open them. This is reasonable under normal circumstances, but when we This becomes a problem when the purpose is to save rather than open.

    Several export methods and their limitations are listed above. In general, Content-Disposition should be a more general method, which takes into account compatibility and avoids browser memory limitations.

data

https://github.com/eligrey/FileSaver.js/wiki/Saving-a-remote-file#using-http-header


热饭班长
3.7k 声望434 粉丝

先去做,做出一坨狗屎,再改进。