Node層模擬實(shí)現(xiàn)multipart表單的文件上傳示例
有時(shí)候就是有這樣的需求,Nodejs做webserver,從瀏覽器端上傳文件到后端服務(wù)器,Node層只是做一個(gè)數(shù)據(jù)中轉(zhuǎn),如果在這個(gè)過(guò)程中,Node webserver需要對(duì)數(shù)據(jù)進(jìn)行適當(dāng)加工,然后再Post到后端,那么就得在Node層模擬文件上傳了。
首先,通過(guò)瀏覽器上傳文件,PostData格式是長(zhǎng)著個(gè)樣子的:

屏幕快照 2014-11-22 下午9.18.45.png
如圖,每一組數(shù)據(jù)其實(shí)就是用“-----WebkitFormBoundary.....”分隔開(kāi)的,最后再用這個(gè)分隔符結(jié)束,而且,這個(gè)分隔符完全是可自定義的。
每一段提交數(shù)據(jù),則通過(guò)Content-Disposition來(lái)描述,未指定Content-Type,則默認(rèn)text/plain,如果是上傳的二進(jìn)制文件,指定其mime-type即可。
簡(jiǎn)單封裝一個(gè)方法,實(shí)現(xiàn)Node層的文件上傳:
/**
* 上傳文件
* @param files 經(jīng)過(guò)formidable處理過(guò)的文件
* @param req httpRequest對(duì)象
* @param postData 額外提交的數(shù)據(jù)
*/
function uploadFile(files, req, postData) {
var boundaryKey = Math.random().toString(16);
var endData = '\r\n----' + boundaryKey + '--';
var filesLength = 0, content;
// 初始數(shù)據(jù),把post過(guò)來(lái)的數(shù)據(jù)都攜帶上去
content = (function (obj) {
var rslt = [];
Object.keys(obj).forEach(function (key) {
arr = ['\r\n----' + boundaryKey + '\r\n'];
arr.push('Content-Disposition: form-data; name="' + key + '"\r\n\r\n');
arr.push(obj[key]);
rslt.push(arr.join(''));
});
return rslt.join('');
})(postData);
// 組裝數(shù)據(jù)
Object.keys(files).forEach(function (key) {
if (!files.hasOwnProperty(key)) {
delete files.key;
return;
}
content += '\r\n----' + boundaryKey + '\r\n' +
'Content-Type: application/octet-stream\r\n' +
'Content-Disposition: form-data; name="' + key + '"; ' +
'filename="' + files[key].name + '"; \r\n' +
'Content-Transfer-Encoding: binary\r\n\r\n';
files[key].contentBinary = new Buffer(content, 'utf-8');
filesLength += files[key].contentBinary.length + fs.statSync(files[key].path).size;
});
req.setHeader('Content-Type', 'multipart/form-data; boundary=--' + boundaryKey);
req.setHeader('Content-Length', filesLength + Buffer.byteLength(endData));
// 執(zhí)行上傳
var allFiles = Object.keys(files);
var fileNum = allFiles.length;
var uploadedCount = 0;
allFiles.forEach(function (key) {
req.write(files[key].contentBinary);
var fileStream = fs.createReadStream(files[key].path, {bufferSize: 4 * 1024});
fileStream.on('end', function () {
// 上傳成功一個(gè)文件之后,把臨時(shí)文件刪了
fs.unlink(files[key].path);
uploadedCount++;
if (uploadedCount == fileNum) {
// 如果已經(jīng)是最后一個(gè)文件,那就正常結(jié)束
req.end(endData);
}
});
fileStream.pipe(req, {end: false});
});
}
思路就這樣,代碼也不復(fù)雜,可能額外需要注意的是,在http.request的response處理中,response.headers可能是gzip的,這個(gè)時(shí)候buffer不能直接toString,需要通過(guò)zlib解碼再轉(zhuǎn)換為string,大概思路:
var result = [];
response.on('data', function (chunk) {
result.push(chunk);
});
// 處理response
var _dealResponse = function (data) {
var buffer = data;
try {
data = data.toString('utf8');
data = data ? (JSON.parse(data) || data) : false;
} catch (err) {
// 接口返回?cái)?shù)據(jù)格式異常,解析失敗
console.log(err);
}
self.res.writeHead(response.statusCode, 'OK', {
'content-type': 'text/plain; charset=utf-8',
'content-length': buffer.length
});
self.res.write(buffer);
self.res.end();
};
response.on('end', function () {
result = Buffer.concat(result);
// gzip 的數(shù)據(jù),需要zlib解碼
if (response.headers['content-encoding'] == 'gzip') {
zlib.gunzip(result, function (err, dezipped) {
var data = err ? new Buffer('{}') : dezipped;
_dealResponse(data);
});
} else {
_dealResponse(result);
}
});
Mark一下,也許你路過(guò)正好需要~~~
以上這篇Node層模擬實(shí)現(xiàn)multipart表單的文件上傳示例就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- nodejs+mongodb aggregate級(jí)聯(lián)查詢操作示例
- Node.js+ES6+dropload.js實(shí)現(xiàn)移動(dòng)端下拉加載實(shí)例
- node微信開(kāi)發(fā)之獲取access_token+自定義菜單
- 詳解nodejs微信公眾號(hào)開(kāi)發(fā)——6.自定義菜單
- JavaScript NodeTree導(dǎo)航欄(菜單項(xiàng)JSON類型/自制)
- nodejs 實(shí)現(xiàn)模擬form表單上傳文件
- Nodejs之http的表單提交
- Nodejs下用submit提交表單提示cannot post錯(cuò)誤的解決方法
- 全面解析node 表單的圖片上傳
- 推薦一個(gè)基于Node.js的表單驗(yàn)證庫(kù)
- node省市區(qū)三級(jí)數(shù)據(jù)性能測(cè)評(píng)實(shí)例分析
相關(guān)文章
利用nodejs讀取圖片并將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成base64格式
這篇文章主要介紹了利用nodejs讀取圖片并將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成base64格式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
Vue+Node實(shí)現(xiàn)的商城用戶管理功能示例
這篇文章主要介紹了Vue+Node實(shí)現(xiàn)的商城用戶管理功能,結(jié)合實(shí)例形式詳細(xì)分析了商城用戶管理的前臺(tái)登錄、校驗(yàn)、跳轉(zhuǎn)、退出等相關(guān)操作技巧,需要的朋友可以參考下2019-12-12
Ubuntu中搭建Nodejs開(kāi)發(fā)環(huán)境過(guò)程分享
這篇文章主要介紹了Ubuntu中搭建Nodejs開(kāi)發(fā)環(huán)境過(guò)程,比較郁悶的是apt-get安裝失敗了,如果有遇到一樣問(wèn)題的朋友,可以參考一下本文2014-06-06
windows使用nvm對(duì)node進(jìn)行版本管理切換的完整步驟
這篇文章主要介紹了windows使用nvm對(duì)node進(jìn)行版本管理切換的完整步驟,在使用之前各位務(wù)必卸載掉自己安裝過(guò)的nvm或者node版本包括環(huán)境變量之類的,要保證自己的電腦完全沒(méi)有node環(huán)境,需要的朋友可以參考下2024-03-03
利用adb shell和node.js實(shí)現(xiàn)抖音搶紅包功能(推薦)
這篇文章主要介紹了利用adb shell和node.js實(shí)現(xiàn)抖音搶紅包功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-02-02
nodejs 使用http進(jìn)行post或get請(qǐng)求的實(shí)例(攜帶cookie)
今天小編就為大家分享一篇nodejs 使用http進(jìn)行post或get請(qǐng)求的實(shí)例(攜帶cookie),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-01-01
nodejs環(huán)境快速操作mysql數(shù)據(jù)庫(kù)的方法詳解
這篇文章主要介紹了nodejs環(huán)境快速操作mysql數(shù)據(jù)庫(kù)的方法詳解,需要的朋友可以參考下2021-03-03

