Several ways for the front-end to download files using Blobs to download files

Several ways for the front-end to download files. Download files using Blobs.
Downloading files on the front-end is a very common requirement. Generally, the back-end will provide two download methods:
1. Directly return the network address of the file (generally used for static files, such as Pictures and various audio and video resources, etc.)
2. Return file stream (generally used for dynamic files, such as exporting different statistical results to excel according to front-end selection, etc.) 

The first method is relatively simple, but has limited usage scenarios.
The second method is more versatile

Let’s first look at the first usage scenario:

-a link

<a href="https://www.baidu.top.pdf">下载文件</a>

We can rename the downloaded file through the download attribute.

<a href="https://www.baidu.top.pdf" download="附件.pdf">下载文件</a>

- You can also use programmatic writing:

1.location href

<script>
  function Download() {
    window.location.href = 'www.baidu.pdf'
  }
</script>

2.window.open

<script>
  function Download() {
    window.open('www.baidu.pdf')
  }
</script>

亿点小知识:When using window.open, browsers other than Google Chrome will intercept the content, but it can be downloaded directly in other browsers.

  • If you want to change it in Google Chrome settings

The second method uses blob file streaming to download

  <script>
    function Download() {
      axios({
        url: "www.baidu.pdf",
        method: 'GET',
        responseType: 'blob', // 这里就是转化为blob文件流,指定响应类型为二进制数据
        headers: {
          // 'Content-Type': 'application/json; application/octet-stream',
          token: 'sss'     // 可以携带token
        }
      }).then(res => {
        const href = URL.createObjectURL(res.data)
        const link = document.createElement('a')
        link.download = '附件.pdf'
        link.href = href
        link.click()
        document.body.removeChild(link);
        URL.revokeObjectURL(href); // 释放内存
      })
    }
  </script>

The following encapsulates the method logic of a blob. If you are interested, you can refer to it.

 // 下载
  const DownloadFile = (row: any) => {
    contractApi
      .xxxApi({ fullFileName: row.filePath })
      .then((blob: any) => {
        row.fileFormat = row.filePath.split('.')[row.filePath.split('.').length - 1]
        download(blob, row.fileFormat, row.fileName)
      })
  }
// file:文件流(一般指后端返回的流); fileType:文件类型/MIME类型;fileName:文件名称
export function download(file: any, fileType: string, fileName?: string) {
  const blob = new Blob([file], { fileType})
  const downloadElement = document.createElement('a')
  const href = window.URL.createObjectURL(blob) // 创建下载的链接
  downloadElement.href = href
  downloadElement.download = fileName // 下载后文件名
  document.body.appendChild(downloadElement)
  downloadElement.click() // 点击下载
  document.body.removeChild(downloadElement) // 下载完成移除元素
  window.URL.revokeObjectURL(href) // 释放掉blob对象
}

// download(blobStream,{ 'Content-Type': 'application/vnd.ms-excel;charset=utf-8' })

3. Blob

1. What is Blob?

Blob (Binary Large Object) represents a large object of binary type. In a database management system, binary data is stored as a collection of single individuals. Blobs are usually image, sound, or multimedia files. In  JavaScript,  objects of type Blob represent immutable raw data like file objects.  In order to feel the Blob object more intuitively, we first use the Blob constructor to create a myBlob object, as shown in the following figure:

As you can see, the myBlob object contains two properties: size and type. The  size attribute is used to represent the size of the data (in bytes), which type is a string of MIME type . Blobs do not necessarily represent data in  JavaScript's  native format. For example  , File the interface is based on  Blob, inherits the functionality of blob and extends it to support files on the user's system. ·

2. Introduction to Blob API

Blob Consists of an optional string  type(usually a MIME type) and  blobParts :

MIME (Multipurpose Internet Mail Extensions) is a type of multipurpose Internet mail extension that sets a file with a certain extension to be opened by an application. When the file with the extension is accessed, the browser will automatically use the specified application to open. It is mostly used to specify some client-defined file names and some media file opening methods. ·

Common MIME types include: hypertext markup language text.html text/html, PNG image.png image/png, ordinary text.txt text/plain, etc.

2.1 Constructor

The syntax of the Blob constructor is:

var aBlob = new Blob(blobParts, options);

The relevant parameters are explained as follows: ·

  • blobParts: It is an array composed of ArrayBuffer, ArrayBufferView, Blob, DOMString and other objects . DOMStrings will be encoded as UTF-8.
  • options: an optional object containing the following two properties:
    • type - The default value is  "", which represents the MIME type of the array contents that will be placed into the blob.
    • endings - The default value is  "transparent", used to specify how strings containing line endings  \n are written. It is one of two values: "native", which means that the line terminator will be changed to a newline character suitable for the host operating system's file system, or  "transparent"it means that the terminator stored in the blob will be left unchanged.

Example 1: Create a Blob from a string

let myBlobParts = ['<html><h2>Hello Semlinker</h2></html>']; // an array consisting of a single DOMString
let myBlob = new Blob(myBlobParts, {type : 'text/html', endings: "transparent"}); // the blob

console.log(myBlob.size + " bytes size");
// Output: 37 bytes size
console.log(myBlob.type + " is the type");
// Output: text/html is the type

  

Example 2: Creating Blobs from Typed Arrays and Strings

let hello = new Uint8Array([72, 101, 108, 108, 111]); // 二进制格式的 "hello"
let blob = new Blob([hello, ' ', 'semlinker'], {type: 'text/plain'});

After introducing the Blob constructor, let's introduce the properties and methods of the Blob class respectively:

2.2 Properties

We already know that the Blob object contains two properties: ·

  • size (read-only): Indicates  Blob the size of the data contained in the object (in bytes).
  • type (read-only): A string indicating  Blob the MIME type of the data contained in this object. If the type is unknown, the value is an empty string.

2.3 Method

  • slice([start[, end[, contentType]]]): Returns a new Blob object that contains the data within the specified range of the source Blob object.
  • stream(): Returns a stream that can read blob contents  ReadableStream.
  • text(): Returns a Promise object containing all the contents of the blob in UTF-8 format  USVString.
  • arrayBuffer(): Returns a Promise object and contains the binary format of all the contents of the blob  ArrayBuffer.

What we need to note here is that Blob objects are immutable . We cannot directly change data in a Blob, but we can split a Blob, create new Blob objects from it, and mix them into a new Blob. This behavior is similar to JavaScript strings: we cannot change the characters in the string, but we can create new corrected strings.

3. Blob usage scenarios

3.1 Multipart upload

File objects are a special type of Blob and can be used in the context of any Blob type. Therefore, for the scenario of large file transfer, we can use the slice method to cut the large file, and then upload it in pieces. The specific example is as follows:


const file = new File(["muzidigbig".repeat(1000000)], "test.txt");

const chunkSize = 40000;
const url = "https://httpbin.org/post";

async function chunkedUpload() {
    for (let start = 0; start < file.size; start += chunkSize) {
        const chunk = file.slice(start, start + chunkSize + 1);
        const fd = new FormData();
        fd.append("data", chunk);

        await fetch(url, { method: "post", body: fd }).then((res) =>
            res.text()
        );
    }
}

3.2 Download data from the Internet

We can download data from the Internet and store the data into Blob objects using the following methods, such as:

const downloadBlob = (url, callback) => {
    const xhr = new XMLHttpRequest()
    xhr.open('GET', url)
    xhr.responseType = 'blob'
    // xhr.headers = { 'Content-Type': 'application/json; application/octet-stream' },
    xhr.onload = () => {
        callback(xhr.response)
    }
    xhr.send(null)
}

Of course, in addition to using  XMLHttpRequest the API, we can also use  fetch the API to obtain binary data in a streaming manner. Here we take a look at how to use the fetch API to obtain online images and display them locally. The specific implementation is as follows:

const myImage = document.querySelector('img');
const myRequest = new Request('flowers.jpg');

fetch(myRequest)
.then(function(response) {
    return response.blob();
})
.then(function(myBlob) {
    let objectURL = URL.createObjectURL(myBlob);
    myImage.src = objectURL;
});

When the fetch request is successful, we call  blob() the method of the response object, read a Blob object from the response object, then use  createObjectURL() the method to create an objectURL, and then assign it to  the attribute img of the element  src to display the image. · 

3.3 blob to file 

        let obj = {
            age: 18,
            sex: '男'
        }
        let content = JSON.stringify(obj)
        // blob类型
        let blob = new Blob([content], {
                type: 'application/json'
            })
        // 将blob转成url
        let url = URL.createObjectURL(blob) //blob:null/244bec7f-e3d3-43d5-803e-f98cc5c8117f  =>链接里面的数据就是右边的内容 {"age":18,"sex":"男"}
        console.log(url)
        //blob转file
        let filename = '文件名'
        var file = new File([blob], filename, {
            type: 'application/json',
            lastModified: Date.now()
        });
        //或者
        var file1 = new File([content], filename, {
            type: 'application/json',
            lastModified: Date.now()
        });
        console.log("文件", file, file1)

3.4 Blob used as URL

Blobs can easily be used as  URLs for <a>, <img> or other tags, and thanks to  type properties we can also upload/download  Blob objects. Below we will give an example of Blob file download, but before looking at the specific example, we have to briefly introduce the Blob URL.

1.Blob URL/Object URL

Blob URL/Object URL is a pseudo-protocol that allows Blob and File objects to be used as URL sources for images, download binary data links, etc. In the browser, we use  URL.createObjectURL the method to create a Blob URL, which receives an  Blob object and creates a unique URL for it, in the form of  blob:<origin>/<uuid>, the corresponding example is as follows:

blob:https://example.org/40a5fb5a-d56d-4a33-b4e2-0acf6a8e5f641

The browser internally  URL.createObjectURL stores a URL → Blob mapping for each generated URL. Therefore, such URLs are shorter but accessible  Blob. The generated URL is only valid while the current document is open. It allows references   ,  <img>but if the blob URL you visit no longer exists, you will receive a 404 error from the browser. ·<a>Blob

The above Blob URL seems very good, but in fact it also has side effects. Although the URL → Blob mapping is stored, the Blob itself still resides in memory and the browser cannot free it. The mapping is automatically cleared when the document is unloaded, so the Blob object is subsequently freed.

However, if the application is long-lived, that won't happen quickly. So if we create a Blob URL, the Blob will exist in memory even if it is no longer needed.

To address this issue, we can call  URL.revokeObjectURL(url) a method that removes the reference from the internal map, allowing the blob to be deleted (if there are no other references), and freeing the memory. Take it

2.Blob file download example

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Blob 文件下载示例</title>
</head>

<body>
    <button id="downloadBtn">文件下载</button>
    <script src="index.js"></script>
</body>
</html>

index.js

const download = (fileName, blob) => {
    const link = document.createElement("a");
    link.href = URL.createObjectURL(blob);
    link.download = fileName;
    link.click();
    link.remove();
    URL.revokeObjectURL(link.href);
};

const downloadBtn = document.querySelector("#downloadBtn");
downloadBtn.addEventListener("click", (event) => {
    const fileName = "blob.txt";
    const myBlob = new Blob(["一文彻底掌握 Blob Web API"], { type: "text/plain" });
    download(fileName, myBlob);
});

In the example, we create a Blob object of type  "text/plain" by calling the Blob constructor  , and then  a download the file by dynamically creating tags. ·

3.5 Blob converted to Base64

URL.createObjectURL An alternative is to  Blob convert to a base64 encoded string. Base64  is a representation method based on 64 printable characters to represent binary data. It is often used in situations where text data is processed to represent, transmit, and store some binary data, including MIME emails and some complex data in XML.

In MIME-formatted emails, base64 can be used to encode binary byte sequence data into text composed of ASCII character sequences. When used, specify base64 in the transfer encoding method. The characters used include 26 uppercase and lowercase Latin letters, 10 numbers, plus sign + and slash /, a total of 64 characters, and the equal sign = is used as a suffix.

Let's introduce how to   embed base64 encoded images in HTML . When writing HTML web pages, for some simple images, you usually choose to embed the image content directly into the web page, thereby reducing unnecessary network requests. However, the image data is binary data, how to embed it? The vast majority of modern browsers support a  Data URLs feature called , which allows the binary data of an image or other file to be encoded using base64 and embedded in a web page as a text string.

Data URLs consist of four parts: a prefix ( data:), a MIME type indicating the data type, an optional  base64 tag if non-text, and the data itself:

data:[<mediatype>][;base64],<data>

mediatype It is a MIME type string, for example " image/jpeg" represents a JPEG image file. If omitted, the default value is  text/plain;charset=US-ASCII. If the data is of type text, you can embed the text directly (using appropriate entity characters or escape characters, depending on the document type). If it is binary data, you can base64 encode the data before embedding it. For example, to embed an image:

<img alt="logo" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...">

However, it should be noted that if the picture is large and the color level of the picture is relatively rich, this method is not suitable, because the base64-encoded string of the picture will be very large, which will significantly increase the size of the HTML page, thus affecting the Loading speed.  In addition, using the FileReader API, we can also easily implement the local preview function of images. The specific code is as follows:

<input type="file" accept="image/*" onchange="loadFile(event)">
<img id="output"/>

<script>
const loadFile = function(event) {
    const reader = new FileReader();
    reader.onload = function(){
        const output = document.querySelector('output');
        output.src = reader.result;
    };
    reader.readAsDataURL(event.target.files[0]);
};
</script>

In the above example, we bind  an onchange event processing function  to the file type input box loadFile. In this function, we create a FileReader object and bind the  onload corresponding event processing function to the object, and then call  readAsDataURL() the method of the FileReader object to save the local image. The corresponding File object is converted into a Data URL. ·

After completing the local image preview, we can directly submit the Data URLs corresponding to the image to the server. In response to this situation, the server needs to do some related processing to save the uploaded images normally. Here, Express is used as an example. The specific processing code is as follows:

const app = require('express')();

app.post('/upload', function(req, res){
    let imgData = req.body.imgData; // 获取POST请求中的base64图片数据
    let base64Data = imgData.replace(/^data:image\/\w+;base64,/, "");
    let dataBuffer = Buffer.from(base64Data, 'base64');
    fs.writeFile("image.png", dataBuffer, function(err) {
        if(err){
            res.send(err);
        }else{
            res.send("图片上传成功!");
        }
    });
});

For the FileReader object, in addition to supporting the conversion of Blob/File objects into Data URLs, it also provides  readAsArrayBuffer() and  readAsText() methods for converting Blob/File objects into other data formats. Here we look at a  readAsArrayBuffer() usage example:

// 从 blob 获取 arrayBuffer
let fileReader = new FileReader();

fileReader.onload = function(event) {
    let arrayBuffer = fileReader.result;    
};
fileReader.readAsArrayBuffer(blob);

Guess you like

Origin blog.csdn.net/muzidigbig/article/details/132343808