最近有在折騰后端node
玲昧,于是想到以前在對(duì)文件進(jìn)行上傳和下載時(shí)遇到一些問(wèn)題孵延,感覺(jué)不是很好處理,說(shuō)到根本原因惶凝,還是對(duì)基礎(chǔ)的原理不是很清晰。
于是苍鲜,現(xiàn)在有了node
環(huán)境混滔,打算使用最原始的方式進(jìn)行文件上傳和下載。也就是說(shuō)前端使用XHR
對(duì)象進(jìn)行文件上傳和下載拳亿,不使用其他ajax
封裝插件肺魁,直接使用瀏覽器原生對(duì)象處理隔节,調(diào)試下瀏覽器會(huì)對(duì)文件上傳和下載處理到哪種程度,而自己又需要寫哪些代碼怎诫。
后端使用express
框架搭建后端服務(wù)幻妓,處理文件上傳時(shí),使用了 multer
插件處理文件上傳强胰。
圖片上傳:
- 前端使用 avatar 作為 key偶洋,上傳文件玄窝。后端使用 avatar 字段接收文件。
- 以下代碼很簡(jiǎn)單恩脂,需要在html中創(chuàng)建一個(gè)input 元素俩块,id 為file(html代碼沒(méi)有展示)典阵。
- 使用formData 對(duì)象處理需要提交的文件壮啊。
- ??使用POST 的方式上傳文件歹啼,這個(gè)需要注意座菠,如果使用url 傳參方式浴滴,例如:使用GET 方式后升略,會(huì)導(dǎo)致url 太長(zhǎng)品嚣,而瀏覽器又對(duì)url長(zhǎng)度進(jìn)行了限制,所以會(huì)導(dǎo)致請(qǐng)求錯(cuò)誤罩旋。
前端代碼:
let fileDom = document.getElementById('file'); // 為input 標(biāo)簽Dom元素
fileDom.onchange = function(e) {
let file = e.target.files[0];
let formData = new FormData();
formData.append('avatar', file);
let xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:3000/web/uploader');
xhr.onload = function() {
console.log(xhr);
}
xhr.send(formData);
}
后端代碼:
- 引入 multer 插件涨醋。
- avatar 對(duì)應(yīng)前端 key册养。
- multer({ dest: 'uploads/'}) 為配置文件儲(chǔ)存路徑球拦。
const multer = require('multer');
var upload = multer({ dest: 'uploads/'}) // 文件儲(chǔ)存路徑
router.post('/uploader', upload.single('avatar'), function(req, res, next) {
let file = req.file;
console.log(file)
res.json({message: "ok"});
});
上圖中
dest: 'uploads/'
為文件儲(chǔ)存路徑,上傳文件后愧膀,可在uploads文件夾中查看已經(jīng)上傳的文件檩淋,如下截圖:
圖片下載代碼
前端代碼
- 使用get 方式請(qǐng)求下載圖片。
-
97d53267175a75dd758a84329950fe25
為文件唯一id(可能為文件的MD5)媚朦, 需要在上傳文件時(shí)询张,將文件Id 和業(yè)務(wù)id 保存在數(shù)據(jù)庫(kù)份氧。為了方便測(cè)試蜗帜,直接在上傳的文件中厅缺,復(fù)制了一個(gè)文件的文件名作為參數(shù)進(jìn)行文件下載店归。
let loadimgDom = document.getElementById('loadimg');
loadimgDom.onclick = function() {
let xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:3000/web/loadimg/97d53267175a75dd758a84329950fe25');
xhr.onload = function(a, b) {
console.log(xhr)
}
xhr.send();
}
后端處理文件下載如下:
router.get('/loadimg/97d53267175a75dd758a84329950fe25', function(req, res, next) {
let imgid = req.param('imgid');
let file = path.join(__dirname,'../../../uploads/' + '97d53267175a75dd758a84329950fe25');
console.log(file);
res.download(file);
});
前端打印返回結(jié)果如下圖1:返回內(nèi)容不是二進(jìn)制消痛,無(wú)法處理文件
解決步驟: 添加 xhr.responseType = "blob";
let loadimgDom = document.getElementById('loadimg');
loadimgDom.onclick = function() {
let xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:3000/web/loadimg/97d53267175a75dd758a84329950fe25');
xhr.onload = function(a, b) {
console.log(xhr)
}
xhr.responseType = "blob";
xhr.setRequestHeader('token',token)
xhr.send();
}
前端打印返回結(jié)果如下圖2:返回內(nèi)容是二進(jìn)制,可以繼續(xù)處理二進(jìn)制下載文件纱新。
下載二進(jìn)制文件,圖片
前端代碼如穆趴, 后端代碼不做修改脸爱;
let loadimgDom = document.getElementById('loadimg');
loadimgDom.onclick = function() {
let xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:3000/web/loadimg/97d53267175a75dd758a84329950fe25');
xhr.onload = function() {
console.log(xhr)
let blob = this.response; //使用response作為返回,而非responseText
let reader = new FileReader();
reader.readAsDataURL(blob); // 轉(zhuǎn)換為base64未妹,可以直接放入a標(biāo)簽href
reader.onload = function(e) {
// 轉(zhuǎn)換完成簿废,創(chuàng)建一個(gè)a標(biāo)簽用于下載
let a = document.createElement("a");
a.download = "圖1.jpg";
a.href = e.target.result;
a.click();
};
}
xhr.responseType = "blob";
xhr.setRequestHeader('token',token)
xhr.send();
}
可下載文件,并且可以打開文件
二進(jìn)制圖片預(yù)覽络它,直接將二進(jìn)制連接放置到img src標(biāo)簽中族檬。src 的url 和使用上面文件下載的url 一樣。
<img src="http://localhost:3000/web/loadimg/97d53267175a75dd758a84329950fe25" alt="">
其實(shí)下圖可以看出化戳, img 標(biāo)簽中单料,src 所對(duì)應(yīng)的鏈接,使用的就就是http GET
方法.