JS-file download, which is also implemented on ios as a download instead of a preview.

Requirements

Through the A link method, the files obtained from the background are downloaded to the local computer, so that they can be downloaded on both mobile and PC terminals.

Question

After requesting the file stream generated by the backend through ajax, a BLOB file is created for downloading. On the PC side and the mobile Android side, it can be downloaded to the local and corresponding mobile phones. On the IOS side, the corresponding blob file address is directly previewed. Instead of downloading the corresponding file stream, the solution can also be downloaded on IOS (Safari browser only)

Steps

1. Through request, the value of responseType is ‘arraybuffer’, request the corresponding file stream

uni.request({
...handleRes,
responseType: 'arraybuffer',
success(res) {
// console.log(res, 'return data');
                    // This is the returned file stream
const file = res.data;
\t\t\t\t\t
},
fail() {
uni.hideLoading();
\t\t\t\t\t
}
})

2. By converting files into blob objects

let blob = null;
if (headerDis.indexOf(tyepList.toString()) != -1) {
blob = new Blob([file], {
type: 'application/octet-stream;charset=UTF-8',
})
} else {
blob = new Blob([file], {
type: headerInfo['content-type'] ||
'application/octet-stream;charset=UTF-8',
})
}

3. Create a link and download through the download attribute

async linkTodownloadFile(blob, fName) {
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveBlob(blob, fName);
return false;
}

const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.style.display = 'none'
link.href = url;
link.setAttribute('download', fName)
document.body.appendChild(link)
if (document.all) {
link.click();
} else {
// Compatible with Firfox
const evt = document.createEvent('MouseEvents');
evt.initEvent('click', true, true);
link.dispatchEvent(evt);
}
document.body.removeChild(link) // Remove element after download is complete
window.URL.revokeObjectURL(url);
uni.hideLoading();
common.toast(107)
}

Note: The main thing here is that if you customize the type of blob on the IOS side, the download attribute will only add the file name without a suffix, which will form a double suffix. And if the type is steam, it will be preview and set to steam If so, the file will be downloaded directly, which is the reason for the judgment in the second step

4. Complete code

uni.request({
url: 'xxx',
responseType: 'arraybuffer',
success(res) {
// console.log(res, 'return data');
const file = res.data;
const headerInfo = res.header;
/** Get file name */
let fName = '';
/** Determine whether it is a customizable type or default */
const tyepList = ['pdf'];

const headerDis = headerInfo['content-disposition'];

if (headerDis) {
const requestFileInfo = headerDis.split(';')[1];
if (store.state.app.SYSTEM_INFO.platform == 'ios') {
if (headerDis.indexOf(tyepList.toString()) != -1) {
fName = requestFileInfo;
} else {
fName = requestFileInfo.split('.')[0];
}

} else {
fName = requestFileInfo;
}
} else {
/** Determine whether the file has a type, if not, use the effect header */
const fType = file.type || headerInfo['content-type'].split(';')[0];
for (const key in fileTypeConfig) {
if (fileTypeConfig[key].indexOf(fType) != -1) {
if (store.state.app.SYSTEM_INFO.platform == 'ios') {
fName = `${fileName}`;
} else {
fName = `${fileName}.${key}`;
}
break
}
}
}

\t\t\t\t\t/** start download */
let blob = null;

if (headerDis.indexOf(tyepList.toString()) != -1) {
blob = new Blob([file], {
type: 'application/octet-stream;charset=UTF-8',
})
} else {
blob = new Blob([file], {
type: headerInfo['content-type'] ||
'application/octet-stream;charset=UTF-8',
})
}

/** Determine whether to perform logical processing for JSON */
if (fName.indexOf('json') != -1) {
//Read data through FileReader
const reader = new FileReader();
// reader.readAsBinaryString(blob);
reader.readAsText(blob, 'utf8');
reader.onload = function() {
var content = JSON.parse(this.result); //This is the parsed data
if (content.code == 200) {
// common.toast(fName);
that.linkTodownloadFile(blob, fName);
resolve();
} else {
isLoading & amp; & amp; uni.hideLoading();
common.toast(content.msg || 400);
}
}
} else {
// common.toast(fName);
that.linkTodownloadFile(blob, fName);
resolve();
}
},
fail() {
uni.hideLoading();
common.toast(108)
reject();
}
})

5. Contents of attachment fileTypeConfig

export default {
xls: 'application/vnd.ms-excel',
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
csv: 'text/csv',
doc: 'application/msword',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
pdf: 'application/pdf',
ppt: 'application/vnd.ms-powerpoint',
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
png: 'image/png',
gif: 'image/gif',
jpeg: 'image/jpeg',
jpg: 'image/jpeg',
mp3: 'audio/mpeg',
aac: 'audio/aac',
html: 'text/html',
css: 'text/css',
js: 'text/javascript',
json: 'application/json',
abw: 'application/x-abiword',
arc: 'application/x-freearc',
avi: 'video/x-msvideo',
azw: 'application/vnd.amazon.ebook',
bin: 'application/octet-stream',
bmp: 'image/bmp',
bz: 'application/x-bzip',
bz2: 'application/x-bzip2',
csh: 'application/x-csh',
eot: 'application/vnd.ms-fontobject',
epub: 'application/epub + zip',
htm: 'text/html',
ico: 'image/vnd.microsoft.icon',
ics: 'text/calendar',
jar: 'application/java-archive',
jsonld: 'application/ld + json',
mid: 'audio/midi audio/x-midi',
midi: 'audio/midi audio/x-midi',
mjs: 'text/javascript',
mpeg: 'video/mpeg',
mpkg: 'application/vnd.apple.installer + xml',
odp: 'application/vnd.oasis.opendocument.presentation',
ods: 'application/vnd.oasis.opendocument.spreadsheet',
odt: 'application/vnd.oasis.opendocument.text',
oga: 'audio/ogg',
ogv: 'video/ogg',
ogx: 'application/ogg',
otf: 'font/otf',
rar: 'application/x-rar-compressed',
rtf: 'application/rtf',
sh: 'application/x-sh',
svg: 'image/svg + xml',
swf: 'application/x-shockwave-flash',
tar: 'application/x-tar',
tif: 'image/tiff',
tiff: 'image/tiff',
ttf: 'font/ttf',
txt: 'text/plain',
vsd: 'application/vnd.visio',
wav: 'audio/wav',
weba: 'audio/webm',
webm: 'video/webm',
webp: 'image/webp',
woff: 'font/woff',
woff2: 'font/woff2',
xhtml: 'application/xhtml + xml',
xml: 'text/xml',
xul: 'application/vnd.mozilla.xul + xml',
zip: 'application/zip,application/x-zip-compressed',

}