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.
- type - The default value is
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);