Node層模擬實(shí)現(xiàn)multipart表單的文件上傳示例
有時(shí)候就是有這樣的需求,Nodejs做webserver,從瀏覽器端上傳文件到后端服務(wù)器,Node層只是做一個(gè)數(shù)據(jù)中轉(zhuǎn),如果在這個(gè)過程中,Node webserver需要對(duì)數(shù)據(jù)進(jìn)行適當(dāng)加工,然后再Post到后端,那么就得在Node層模擬文件上傳了。
首先,通過瀏覽器上傳文件,PostData格式是長(zhǎng)著個(gè)樣子的:
屏幕快照 2014-11-22 下午9.18.45.png
如圖,每一組數(shù)據(jù)其實(shí)就是用“-----WebkitFormBoundary.....”分隔開的,最后再用這個(gè)分隔符結(jié)束,而且,這個(gè)分隔符完全是可自定義的。
每一段提交數(shù)據(jù),則通過Content-Disposition來描述,未指定Content-Type,則默認(rèn)text/plain,如果是上傳的二進(jìn)制文件,指定其mime-type即可。
簡(jiǎn)單封裝一個(gè)方法,實(shí)現(xiàn)Node層的文件上傳:
/** * 上傳文件 * @param files 經(jīng)過formidable處理過的文件 * @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過來的數(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,需要通過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一下,也許你路過正好需要~~~
以上這篇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微信開發(fā)之獲取access_token+自定義菜單
- 詳解nodejs微信公眾號(hào)開發(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)文章
node.js調(diào)用Chrome瀏覽器打開鏈接地址的方法
其實(shí)在Node.JS中打開瀏覽器網(wǎng)址非常簡(jiǎn)單,但還是有必要整理下分享給有需要的朋友們,這篇文章主要給大家介紹了node.js如何調(diào)用Chrome瀏覽器打開鏈接地址的方法,文中介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起看看吧。2017-05-05node.js與C語言 實(shí)現(xiàn)遍歷文件夾下最大的文件,并輸出路徑,大小
這篇文章主要介紹了node.js與C語言 實(shí)現(xiàn)遍歷文件夾下最大的文件,并輸出路徑,大小的相關(guān)資料,需要的朋友可以參考下2017-01-01express框架實(shí)現(xiàn)基于Websocket建立的簡(jiǎn)易聊天室
本篇文章主要介紹了express框架實(shí)現(xiàn)基于Websocket建立的簡(jiǎn)易聊天室,具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08Node實(shí)現(xiàn)前端本地開發(fā)接口代理服務(wù)
本文主要介紹了Node實(shí)現(xiàn)前端本地開發(fā)接口代理服務(wù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05使用nvm實(shí)現(xiàn)多個(gè)nodejs版本的快速切換
NodeJS的升級(jí)比較快,在開發(fā)中要使用最新的版本,必須經(jīng)常升級(jí),但對(duì)于一些老項(xiàng)目可能又要使用低版本的NodeJS,使用nvm工具可以方便的管理下載的NodeJS版本,并通過命令實(shí)現(xiàn)NodeJS版本的快速切換,需要的朋友可以參考下2024-09-09node.js Promise對(duì)象的使用方法實(shí)例分析
這篇文章主要介紹了node.js Promise對(duì)象的使用方法,結(jié)合實(shí)例形式分析了node.js中Promise對(duì)象的功能、定義、調(diào)用方法及相關(guān)使用技巧,需要的朋友可以參考下2019-12-12node.js安裝及環(huán)境配置超詳細(xì)步驟講解(Windows系統(tǒng)安裝包方式)
這篇文章主要介紹了node.js安裝及環(huán)境配置超詳細(xì)教程(Windows系統(tǒng)安裝包方式),本文分步驟通過圖文并茂的形式給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02