express+multer上傳圖片打開亂碼問題及解決
express+multer上傳圖片打開亂碼
原因
由于使用multer處理上傳圖片時,multer存儲的是重命名的文件,文件并沒有后綴名導(dǎo)致文件無法在服務(wù)器直接打開,手動加上后綴名就能打開文件。
如:
解決方法
引入fs模塊將文件重命名存儲即可,以下用單文件上傳為例:
const fs=require('fs') router.post('/imageUpload',upload.single('avatar'),function (req, res) { console.log(req.file) //獲取文件后綴名 var appendName=req.file.originalname.split('.')[1] //fs重命名文件,第一個參數(shù)為上傳文件絕對路徑,第二個參數(shù)為相對路徑 //第三個參數(shù)可選 fs.rename(req.file.path,`tmp/uploads/${req.file.filename}.${appendName}`,function (err) { if (err) throw err }) res.json({msg:'success'}) })
簡單的node文件上傳下載及中文亂碼
1. 基于MEAN的技術(shù)棧
使用restful風(fēng)格的接口
2. 在前端代碼中放置文件上傳按鈕和處理表單數(shù)據(jù)
<div class="upload-file btn btn-sm btn-primary mb-2"> ? <span><i class="fa fa-upload"></i> Upload</span> ? <input type="file" class="btn btn-sm btn-primary mb-2" (change)="fileChange($event, topic)" placeholder="Upload file" accept=".csv,.xls"> </div>
處理上傳文件,生成表單數(shù)據(jù)
fileChange(event, topic) { this.topic = topic; const fileList: FileList = event.target.files; const file: File = fileList[0]; const formData: FormData = new FormData(); formData.append('_id', topic._id); formData.append('file', file, file.name); this.topicService.uploadMark(formData).subscribe((res) => { this.topic.marks = res; this.toast.setMessage('item import successfully.', 'success'); }, error => console.log(error)); }
uploadMark(fileData: FormData): Observable<any> { return this.http.post('/api/upload', fileData); }
3. 后端接收上傳文件
文件上傳的router
export default function setRoutes(app) { ? const router = express.Router(); // file uplaod router.route('/upload').post(uploadCtrl.uploadFile); // Apply the routes to our application with the prefix /api app.use('/api', router); }
在路由中,req的file字段是獲取不到上傳文件的,或許可以通過設(shè)置bodyParser來處理,但我這里使用一個比較常見的庫multer。
npm install multer --save import * as path from 'path'; import * as multer from 'multer'; import TopicService from '../services/topic'; export default class UploadCtrl { ? uploadFile = (req, res) => { ? ? const topicService = new TopicService(); ? ? // 獲取上傳文件 ? ? const uploading = multer({ ? ? ? dest: path.join(__dirname, '../public/uploads'), ? ? }).single('file'); // 這里的file是formData.append('file', file, file.name)里的名稱 ? ? uploading(req, res, (err) => { ? ? ? if (err) { ? ? ? ? return console.error(err); ? ? ? } ? ? ? const topicId = req.body._id; ? ? ? const uploadFile = req.file; ? ? ? // 保存數(shù)據(jù) ? ? ? const save = async () => { ? ? ? ? const markList = await topicService.parseMark(uploadFile.path); ? ? ? ? const db = await topicService.saveDB(topicId, markList); ? ? ? ? return { ? ? ? ? ? markList: markList, ? ? ? ? ? db: db, ? ? ? ? }; ? ? ? }; ? ? ? save().then((result) => { ? ? ? ? res.status(200).json(result.markList); ? ? ? }, error => { ? ? ? ? console.error(error); ? ? ? }); ? ? }); ? } }
4. 處理上傳文件的亂碼
上傳的文件是一個中文的csv,解析時出現(xiàn)了亂碼,使用iconv-lite進行轉(zhuǎn)換
npm install iconv-lite --save import * as iconv from 'iconv-lite'; import * as Buffer from 'bufferhelper'; export default class IconvHelper { ? /** ? ?* 用于文件上傳的轉(zhuǎn)碼 ? ?* @param fileStr ? ?* @returns {string} ? ?*/ ? static iconv2utf8 = (fileStr) => { ? ? return iconv.decode(fileStr, 'gbk'); ? } ? /** ? ?* 用于文件下載的轉(zhuǎn)碼 ? ?* @param fileStr ? ?* @returns {NodeBuffer} ? ?*/ ? static iconv2gbk = (fileStr) => { ? ? return iconv.encode(fileStr, 'gbk'); ? } }
bufferhelper是一個buffer的增強類,但這里使用后并不能正確賦值,所以這里暫且沒有使用
對csv文件進行解析,生成數(shù)組,下一步可以保存到數(shù)據(jù)庫
parseMark = (filePath) => { ? return new Promise((resolve, reject) => { ? ? // 讀取文件內(nèi)容 ? ? fs.readFile(filePath, (error, data) => { ? ? ? if (error) { ? ? ? ? return reject(error); ? ? ? } ? ? ? const text = IconvHelper.iconv2utf8(data); ? ? ? const markList = []; ? ? ? // 將文件按行拆成數(shù)組 ? ? ? text.split(/\r?\n/).forEach((line, index) => { ? ? ? ? const arr = line.split(','); ? ? ? ? if (index > 0 && arr[0]) { ? ? ? ? ? markList.push({ ? ? ? ? ? ? userId: arr[0], ? ? ? ? ? ? username: arr[1], ? ? ? ? ? ? donePageCount: arr[2], ? ? ? ? ? ? areaCount: arr[4], ? ? ? ? ? ? name: arr[6], ? ? ? ? ? }); ? ? ? ? } ? ? ? }); ? ? ? resolve(markList); ? ? }); ? }); }
5. 下載文件
res.setHeader('Content-disposition', `attachment; filename='${result.name}-member.csv'`); res.setHeader('Content-type', 'text/csv; charset=GBK'); res.end(IconvHelper.iconv2gbk(content));
6. 處理下載文件的亂碼
由于node.js只支持'ascii', 'utf8', 'base64', 'binary'的編碼方式,不支持MS的utf8 + BOM格式,網(wǎng)上有說增加BOM頭,如下示:
const msExcelBuffer = Buffer.concat([ ? new Buffer('\xEF\xBB\xBF', 'binary'), ? new Buffer(IconvHelper.iconv2gbk(content)) ]);
但實際并沒有起作用,最后只是簡單的encode成gbk問題得到解決
res.end(IconvHelper.iconv2gbk(content));
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
使用NODE.JS創(chuàng)建一個WEBSERVER(服務(wù)器)的步驟
在 node.js 中創(chuàng)建一個服務(wù)器非常簡單,只需要使用 node.js 為我們提供的 http 模塊及相關(guān) API 即可創(chuàng)建一個麻雀雖小但五臟俱全的web 服務(wù)器,相比 Java/Python/Ruby 搭建web服務(wù)器的過程簡單的很。本文簡單的講解下實現(xiàn)步驟2021-06-06解決Node.js使用MySQL出現(xiàn)connect ECONNREFUSED 127.0.0.1:3306的問題
這篇文章主要介紹了解決Node.js使用MySQL出現(xiàn)connect ECONNREFUSED 127.0.0.1:3306報錯的相關(guān)資料,文中將問題描述的很清楚,解決的方法也介紹的很完整,需要的朋友可以參考借鑒,下面來一起看看吧。2017-03-03在Linux上用forever實現(xiàn)Node.js項目自啟動
在一臺計算機上手動跑Node項目簡單,node xx.js就搞定了,想讓Node項目后臺運行,雖然不能直接用node命令搞定,但是在安裝了forever這個包以后,還是很輕松的。不過要是在遠程服務(wù)器上構(gòu)建Node項目,如果沒法自啟動,一旦服務(wù)器重啟,那就麻煩了。2014-07-07解決npm?run?serve啟動報錯npm?ERR?Missing?script:"serve&q
這篇文章主要給大家介紹了關(guān)于解決npm?run?serve啟動報錯npm?ERR?Missing?script:"serve"的相關(guān)資料,這是最近開發(fā)中遇到的一個問題,文中通過圖文將解決辦法介紹的非常詳細,需要的朋友可以參考下2023-01-01nodejs基于WS模塊實現(xiàn)WebSocket聊天功能的方法
這篇文章主要介紹了nodejs基于WS模塊實現(xiàn)WebSocket聊天功能的方法,結(jié)合實例形式分析了nodejs使用WS模塊進行WebSocket通信實現(xiàn)聊天功能的具體操作技巧,需要的朋友可以參考下2018-01-01nodejs body-parser 解析post數(shù)據(jù)實例
下面小編就為大家?guī)硪黄猲odejs body-parser 解析post數(shù)據(jù)實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-07-07