express+multer上傳圖片打開亂碼問題及解決
express+multer上傳圖片打開亂碼
原因
由于使用multer處理上傳圖片時(shí),multer存儲的是重命名的文件,文件并沒有后綴名導(dǎo)致文件無法在服務(wù)器直接打開,手動(dòng)加上后綴名就能打開文件。
如:

解決方法
引入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重命名文件,第一個(gè)參數(shù)為上傳文件絕對路徑,第二個(gè)參數(shù)為相對路徑
//第三個(gè)參數(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來處理,但我這里使用一個(gè)比較常見的庫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. 處理上傳文件的亂碼
上傳的文件是一個(gè)中文的csv,解析時(shí)出現(xiàn)了亂碼,使用iconv-lite進(jìn)行轉(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是一個(gè)buffer的增強(qiáng)類,但這里使用后并不能正確賦值,所以這里暫且沒有使用
對csv文件進(jìn)行解析,生成數(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))
]);但實(shí)際并沒有起作用,最后只是簡單的encode成gbk問題得到解決
res.end(IconvHelper.iconv2gbk(content));
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
使用NODE.JS創(chuàng)建一個(gè)WEBSERVER(服務(wù)器)的步驟
在 node.js 中創(chuàng)建一個(gè)服務(wù)器非常簡單,只需要使用 node.js 為我們提供的 http 模塊及相關(guān) API 即可創(chuàng)建一個(gè)麻雀雖小但五臟俱全的web 服務(wù)器,相比 Java/Python/Ruby 搭建web服務(wù)器的過程簡單的很。本文簡單的講解下實(shí)現(xiàn)步驟2021-06-06
基于websocket實(shí)現(xiàn)簡單聊天室對話
這篇文章主要為大家詳細(xì)介紹了基于websocket實(shí)現(xiàn)簡單聊天室對話,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07
解決Node.js使用MySQL出現(xiàn)connect ECONNREFUSED 127.0.0.1:3306的問題
這篇文章主要介紹了解決Node.js使用MySQL出現(xiàn)connect ECONNREFUSED 127.0.0.1:3306報(bào)錯(cuò)的相關(guān)資料,文中將問題描述的很清楚,解決的方法也介紹的很完整,需要的朋友可以參考借鑒,下面來一起看看吧。2017-03-03
在Linux上用forever實(shí)現(xiàn)Node.js項(xiàng)目自啟動(dòng)
在一臺計(jì)算機(jī)上手動(dòng)跑Node項(xiàng)目簡單,node xx.js就搞定了,想讓Node項(xiàng)目后臺運(yùn)行,雖然不能直接用node命令搞定,但是在安裝了forever這個(gè)包以后,還是很輕松的。不過要是在遠(yuǎn)程服務(wù)器上構(gòu)建Node項(xiàng)目,如果沒法自啟動(dòng),一旦服務(wù)器重啟,那就麻煩了。2014-07-07
解決npm?run?serve啟動(dòng)報(bào)錯(cuò)npm?ERR?Missing?script:"serve&q
這篇文章主要給大家介紹了關(guān)于解決npm?run?serve啟動(dòng)報(bào)錯(cuò)npm?ERR?Missing?script:"serve"的相關(guān)資料,這是最近開發(fā)中遇到的一個(gè)問題,文中通過圖文將解決辦法介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01
nodejs基于WS模塊實(shí)現(xiàn)WebSocket聊天功能的方法
這篇文章主要介紹了nodejs基于WS模塊實(shí)現(xiàn)WebSocket聊天功能的方法,結(jié)合實(shí)例形式分析了nodejs使用WS模塊進(jìn)行WebSocket通信實(shí)現(xiàn)聊天功能的具體操作技巧,需要的朋友可以參考下2018-01-01
nodejs body-parser 解析post數(shù)據(jù)實(shí)例
下面小編就為大家?guī)硪黄猲odejs body-parser 解析post數(shù)據(jù)實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07

