First, introduction and demand

1.1,

XMLHttpRequest is used to exchange data with the server in the background. This means that part of a web page can be updated without reloading the entire page.

Problem :Chrome automatically invokes the built-in PDF reader to open

1.2, the demand for

On Google Chrome, use the A tag to download the PDF link file. If the PDF file is in the same domain, you can download it directly. But if the domain is different, instead of downloading, open the page to preview the file. But the requirement is to download the file directly, not open the preview; And download the file stream returned in the background.

Two, download files

The downloaded NPM package is web-downloadfile. Run the following command to install it and use it

cnpm install web-downloadfile –save

Currently only three apis are available, as follows:

import { base64ToFileOrBlob, saveFileToBlob, saveFileToLink } from ‘web-downloadfile’;

For details, see the official website web-downloadfile

2.1, the train of thought

Through the Download attribute of a tag, we can directly download the data stream files returned by the background interface. Therefore, can we simulate sending HTTP requests and convert file links into file streams for a tag download? The following describes the ideas and methods of link file to file stream download

2.2. File path to file flow

1. Verify whether it is a path link

Verify that the URL is valid using the regular expression

1 let reg = /^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(([A-Za-z0-9-~]+).) +([A-Za-z0-9-~\/])+$/; 2 if (! Reg.test (url)) {3 throw new Error(" invalid parameter passed, not standard link "); 4}Copy the code

2. Create the XMLHttpRequest object

Simulate sending an HTTP request to obtain a file stream

1 let xhr = new XMLHttpRequest(); // Create the XMLHttpRequest object 2 xhr.open('get', 'http://url', true); // Specify the type of request, URL, and whether the request is processed asynchronously. The three parameters are method: the request type; GET or POST URL: file location on the server async: true or false 3 xhr.setrequestheader (' content-type ', 'application/ PDF'); Xhr. responseType = "blob"; 5 xhr.onload = function () {6 if (this.status == 200) {7 var blob = accept binary stream this.response; 9 } 10 } 11 xhr.send(); // Send the request to the serverCopy the code

3. Complete method

3 * @param url: file link 4 * @param fileName: fileName; 5 * @param type: indicates the file type. 6 */ 7 function fileLinkToStreamDownload(url, fileName, type) { 8 let reg = /^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(([A-Za-z0-9-~]+).) +([A-Za-z0-9-~\/])+$/; 9 if (! Reg.test (url)) {10 throw new Error(" invalid parameter passed, not standard file link "); 11 } else { 12 let xhr = new XMLHttpRequest(); 13 xhr.open('get', url, true); 14 xhr.setRequestHeader('Content-Type', `application/${type}`); 15 xhr.responseType = "blob"; 16 xhr.onload = function () {17 if (this.status == 200) {17 var blob = this.response; 20 downloadExportFile(blob, fileName, type) 21 } 22 } 23 xhr.send(); 25 24}}Copy the code

2.3. Download files

1. Create a download link

1 let downloadElement = document.createElement('a'); 2 let href = blob; 3 if (typeof blob == 'string') { 4 downloadElement.target = '_blank'; / / if it is a link to open a new TAB to download 5} else {6 href = window. URL. CreateObjectURL (blob); 7} 8 downloadelement. href = href; // Download the linkCopy the code

2. Simulate clicking the download link

1 downloadElement.download = tagFileName + moment(new Date().getTime()).format('YYYYMMDDhhmmss') + '.' + fileType; / / download the file name after 2 document. The body. The appendChild (downloadElement); 3 downloadElement.click(); // Click downloadCopy the code

3. Release resources after downloading

1 document.body.removeChild(downloadElement); // Remove element 2 if (typeof blob! = 'string') { 3 window.URL.revokeObjectURL(href); // Release blob object 4}Copy the code

4. Completion method

1 /** 2 * Download export file 3 * @param blob: BloB object or link that returns data 4 * @param tagFileName: file name tag after download 5 * @param fileType: 5 */ 7 function downloadExportFile(blob, tagFileName, fileType) { 8 let downloadElement = document.createElement('a'); 9 let href = blob; 10 if (typeof blob == 'string') { 11 downloadElement.target = '_blank'; 12 } else { 13 href = window.URL.createObjectURL(blob); Download element. href = href; 16 downloadElement.download = tagFileName + moment(new Date().getTime()).format('YYYYMMDDhhmmss') + '.' + fileType; / / download the file name after 17 document. The body. The appendChild (downloadElement); 18 downloadElement.click(); / / click download 19 document. Body. RemoveChild (downloadElement); 20 if (typeof blob! = 'string') { 21 window.URL.revokeObjectURL(href); // Release blob object 22} 23 24}Copy the code

2.4, Base64 object to file object

Mainly for images, but other files are also acceptable

1 /** 2 * Base64 object to file object 3 * @param urlData: data base64 object 4 * @param type: type image/ PNG; 5 */ function base64ToBlob(urlData, type) {8 let arr = urldata.split (','); 9 let array = arr[0].match(/:(.*?) ; /) 10 let mime = (array && array.length > 1 ? array[1] : type) || type; 11 // Remove the url header and convert it to byte 12 let bytes = window.atob(arr[1]); 14 let ab = new ArrayBuffer(bytes.length); 14 Let ab = new ArrayBuffer(bytes.length); 16 let ia = new Uint8Array(ab); 17 for (let i = 0; i < bytes.length; i++) { 18 ia[i] = bytes.charCodeAt(i); 19 } 20 return new Blob([ab], { 21 type: mime 22 }); 23}Copy the code

2.5. Example

1. File link to file stream download

1 fileLinkToStreamDownload (' http://127.0.0.1/download.pdf ', 'download file instance', 'PDF')Copy the code

2, Base64 object to file object download

1 let blob = base64ToBlob('data:image/png; base64,iVBORw0KGgo=... ','image/ PNG ') downloadExportFile(blob, 'download', 'PNG ')Copy the code

Problem record: The browser cache is faulty

Due to the browser’s caching mechanism, when we make a request using XMLHttpRequest, the browser will compare the requested address to the address in the cache, and if the same record exists, it will return the same content as the last request without making a request to the server.

Solutions to this type of caching problem:

**1,** timestamp method – that is, each request URL is followed by a string of the current time or other similar random string that will not repeat, so that the browser sends a different URL each time, it will be treated as a different request, not read from the cache.

1 the if (url. IndexOf ("?" ) > = 0) {/ / whether the url is with parameter url = 2 + url "& t =" + (new Date ()). The valueOf (); 3 }else{ 4 url = url + "? t=" + (new Date()).valueOf(); 5}Copy the code

2, before XMLHttpRequest sends the request:

Add the If – Modified – Since the head

1 XHR. SetRequestHeader (" the if-modified-since ", "0"); 2 xhr.send(null);Copy the code

This article is from www.cnblogs.com/jackson-yqj…