Node.js 文件上傳中文文件名亂碼問題,為什么只有Node會有亂碼問題,其他后端框架少見?

問題現象

當用戶上傳包含中文字符的文件時,在服務器端獲取到的文件名可能變成類似??μ?èˉ???????.txt?這樣的亂碼,而不是預期的中文文件名。

為什么只有Node會亂碼?

  • 很多后端框架(如 Java Spring Boot、Python Django、PHP Laravel)為了簡化開發,在底層已經處理了 “編碼不匹配” 問題,開發者感知不到。
  • Node.js 的核心特點是 “輕量、原生模塊僅提供基礎能力,不做過度封裝”,這導致它沒有默認解決編碼問題,需要開發者手動處理

問題根源

首先了解 HTTP 協議和 Node.js 處理請求的方式:

  1. HTTP 協議的歷史遺留問題:早期的 HTTP 協議主要設計用于傳輸英文內容,默認采用?latin1(ISO-8859-1)編碼。

  2. 表單提交的編碼方式:當通過?multipart/form-data?格式上傳文件時,瀏覽器會使用?latin1?編碼來傳輸文件名等元數據,即使其中包含非拉丁字符。

  3. Node.js 的默認處理:Node.js 在解析請求時,默認會將這些?latin1?編碼的數據直接轉換為字符串,而?latin1?無法正確表示中文字符,從而導致亂碼

簡單來說,中文文件名被瀏覽器以?latin1?編碼傳輸,但 Node.js 沒有正確解碼,導致了亂碼現象。

latin1?是一種適合西歐語言的單字節編碼,因歷史原因成為早期互聯網的默認編碼,也因此導致了中文等多字節字符在傳輸中的亂碼問題


解決方案

一、接收前端傳遞:解決這個問題的關鍵在于正確地解碼文件名。我們可以使用 Node.js 的 Buffer 類來實現這一轉換:

// 將亂碼的文件名轉換為正確的中文
const correctFilename = Buffer.from(originalname, "latin1").toString("utf8");
第一步:Buffer.from (originalname, "latin1")
  • originalname?是從請求中獲取的原始文件名(已被錯誤解碼為亂碼)
  • 第二個參數?"latin1"?表示:把亂碼的字符串按照?latin1?編碼重新轉換為字節序列
  • 這一步的作用是還原瀏覽器發送時的原始字節數據
第二步:.toString ("utf8")
  • 將上一步得到的原始字節序列,用正確的編碼(utf8)重新解碼為字符串
  • 這一步會把之前被拆分為單字節的中文字符重新組合為正確的多字節表示

為什么這樣有效?

  • latin1?編碼的特性是:每個字符都直接對應一個字節(0-255),不會丟失信息
  • 即使原始字符是 UTF-8 編碼,用?latin1?解碼成亂碼后,依然可以通過反向操作還原
  • 這是一種 "-lossless"(無損失)的轉換方式,專門用于修復此類編碼不匹配問題

二、返回前端響應:同時,為了確保服務器返回的響應中中文能正確顯示,我們需要設置響應頭的字符集

告訴瀏覽器:“我(服務器)成功處理了你的請求,接下來會返回一段 HTML 格式的內容,并且這段內容是用 UTF-8 編碼的,請你用 HTML 規則渲染、用 UTF-8 解碼,確保界面正常顯示且中文不亂碼”。

// 設置響應頭,確保中文正常顯示
res.writeHead(200, {'Content-Type': 'text/html;charset=utf-8'});

建議放置到全局中間件

// 全局編碼處理中間件
app.use((req, res, next) => {// 設置響應頭確保UTF-8編碼res.setHeader('Content-Type', 'application/json; charset=utf-8');// 處理請求中的文件名編碼問題if (req.headers['content-type'] && req.headers['content-type'].includes('multipart/form-data')) {// 對于multipart/form-data請求,確保正確處理文件名編碼req.setEncoding = 'utf8';}next();
});

完整示例(原生Nodejs示列)

const http = require('http');
const fs = require('fs');
const path = require('path');// 創建服務器
const server = http.createServer((req, res) => {// 處理 GET 請求 - 顯示上傳表單if (req.method === 'GET') {res.writeHead(200, { 'Content-Type': 'text/html;charset=utf-8' });res.end(`<form method="POST" enctype="multipart/form-data"><input type="file" name="file" /><button type="submit">上傳文件</button></form>`);return;}// 處理 POST 請求 - 處理文件上傳if (req.method === 'POST' && req.headers['content-type'].startsWith('multipart/form-data')) {// 獲取分隔符const boundary = req.headers['content-type'].split('; ')[1].split('=')[1];let fileName = '';let fileData = [];let isFilePart = false;// 接收數據req.on('data', (chunk) => {// 轉換為字符串用于解析文件名(臨時用 latin1)const chunkStr = chunk.toString('latin1');// 提取并處理文件名(核心解決方案)if (!fileName && chunkStr.includes('filename="')) {const match = chunkStr.match(/filename="(.*?)"/);if (match && match[1]) {// 關鍵步驟:修復中文文件名亂碼// 將 latin1 編碼的文件名重新解碼為 utf8fileName = Buffer.from(match[1], 'latin1').toString('utf8');}}// 收集文件內容if (fileName && !isFilePart && chunkStr.includes('\r\n\r\n')) {isFilePart = true;const start = chunkStr.indexOf('\r\n\r\n') + 4;fileData.push(chunk.slice(start - chunk.length));} else if (isFilePart && !chunkStr.includes(`--${boundary}--`)) {fileData.push(chunk);}});// 數據接收完成,保存文件req.on('end', () => {if (!fileName) {res.writeHead(400, { 'Content-Type': 'text/html;charset=utf-8' });return res.end('未找到文件');}// 合并并清理文件內容const fileBuffer = Buffer.concat(fileData);const endIndex = fileBuffer.lastIndexOf(Buffer.from(`--${boundary}--`));const cleanData = endIndex > 0 ? fileBuffer.slice(0, endIndex - 2) : fileBuffer;// 保存文件const savePath = path.join(__dirname, 'uploads', fileName);fs.writeFile(savePath, cleanData, (err) => {// 關鍵:設置響應編碼為 utf8,確保返回中文正常顯示res.writeHead(err ? 500 : 200, { 'Content-Type': 'text/html;charset=utf-8' });res.end(err ? '上傳失敗' : `文件上傳成功: ${fileName}`);});});}
});// 啟動服務器
const PORT = 3000;
server.listen(PORT, () => {console.log(`服務器運行在 http://localhost:${PORT}`);// 創建上傳目錄if (!fs.existsSync('./uploads')) fs.mkdirSync('./uploads');
});

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/97995.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/97995.shtml
英文地址,請注明出處:http://en.pswp.cn/web/97995.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

學習英語音標 (從漢語角度看英語音標發音差異)

僅供參考, 跟著教學視頻看不懂時再來看以下引導 以下只寫容易出錯的音標 發音視頻: https://www.jiwake.com/yinbiaofayin/ 音標規則單詞??類似漢語e, 餓~urge?類似漢語e, 餓go??類似漢語o, 哦~walk?類似漢語o, 哦wash?/i?/的短語, 不止發聲短,舌頭不用隆起it?類似漢…

論文筆記(九十一)GWM: Towards Scalable Gaussian World Models for Robotic Manipulation

GWM: Towards Scalable Gaussian World Models for Robotic Manipulation文章概括摘要1. 引言2. 相關工作3. 高斯世界模型&#xff08;Gaussian World Model&#xff09;3.1. 世界狀態編碼&#xff08;World State Encoding&#xff09;3.2. 基于擴散的動態建模&#xff08;Dif…

apache phoenix sql 命令大全詳解

這是一份非常詳細的 Apache Phoenix SQL 命令大全和詳解。Phoenix 作為 HBase 上的 SQL 層&#xff0c;其語法大部分與標準 SQL 兼容&#xff0c;但也有許多針對 HBase 的特性擴展。核心概念 在開始之前&#xff0c;請記住 Phoenix 的兩個核心概念&#xff1a; 主鍵&#xff08…

【代碼講解】SO-ARM100 雙場景演示:手柄驅動 Mujoco 仿真 + 實機控制

視頻講解&#xff1a; 【代碼講解】SO-ARM100 雙場景演示&#xff1a;手柄驅動 Mujoco 仿真 實機控制今天介紹下使用使用北通手柄通過控制 Mujoco 中的 SO-ARM100 機械臂&#xff0c;然后將關節數據通過 zmq 通信轉發控制實際機械臂。 本期中會涉及如下點&#xff0c;需要注意…

「數據獲取」《中國教育經費統計年鑒》(1997-2024)

01、數據簡介《中國教育經費統計年鑒》作為我國教育經費領域的核心統計典籍&#xff0c;全面系統地呈現了全國各級各類教育經費的來源構成、分配流向與使用成效。其統計范圍覆蓋學前教育、基礎教育、中等職業教育、高等教育及特殊教育等全學段&#xff0c;數據維度涵蓋財政性教…

使用 Logspout 收集所有容器的

1.將所有容器的輸出路由到遠程 rsyslog 服務器1.修改 rsyslog 配置文件/etc/rsyslog.conf, 從中找到 “# Provides UDP sysilog recepion"語句。并將該處的以下兩行配置代碼行首的“#”字符刪除&#xff08;取消注釋&#xff09;[roothost1 ~]# vi /etc/rsyslog.conf [roo…

【智能化解決方案】基于多目標優化檢索增強生成的智能行程規劃方案

&#x1f4dd; 基于多目標優化的智能行程規劃方案 1 用戶需求分析與矩陣構建 1.1 核心用戶信息提取 根據用戶提供的年齡、出發地、目的地、出行時間等基本信息&#xff0c;我們首先構建一個用戶特征向量&#xff1a; U {Age, Origin, Destination, TravelDate, Duration, Budg…

軟件研發的演變

軟件研發從一門手工作坊式的藝術&#xff0c;逐步演進為一門系統化、工程化、智能化的現代學科。其發展歷程不僅體現了技術的飛躍&#xff0c;更反映了方法論、協作模式和思維方式的深刻變革。一、發展演變歷程軟件研發的演變可以大致劃分為以下幾個階段&#xff1a;1. 軟件作坊…

「日拱一碼」091 機器學習——集成學習

目錄 集成學習介紹 1. 核心思想 2. 為什么有效&#xff1f; 3. 主要流派與方法 A. 并行方法&#xff1a;Bagging (Bootstrap Aggregating) B. 串行方法&#xff1a;Boosting C. 堆疊法&#xff1a;Stacking 代碼示例 Bagging 的代表 —— 隨機森林 (Random Forest) 集成…

vscode實現第三方包的使用,cmake結合vcpkg(跨平臺)

要使用cmake和vcpkg組織一個完整的現代cpp項目&#xff0c;一般來說需要三個文件vcpkg.json描述第三方依賴項//vcpkg.json {"dependencies": ["fmt"] }//安裝,在vcpkg.json目錄執行 vcpkg installCMakePresets.json定義項目的本質屬性&#xff08;What&…

DevExpress中Word Processing Document API學習記錄

文章目錄1 文檔結構劃分2 文檔操作基礎2.1 Positions and Ranges2.2 Secitions2.3 Paragraphs2.4 Tables2.5 Lists2.6 Hyperlinks and Bookmarks2.7 Comments2.8 Headers and Footers2.9 Shapes and Pictures2.10 Watermarks2.11 Charts2.12 OLE Objects2.13 ActiveX Controls2…

Roo Code 的差異_快速編輯功能

什么是差異編輯&#xff1f; 簡單來說&#xff0c;差異編輯就像是一位細心的裝修師傅&#xff1a;他不會把整個房子拆掉重蓋&#xff0c;而是精準地只修補需要改動的部分。Roo Code 的這項功能默認開啟&#xff0c;它通過比對代碼差異&#xff08;diff&#xff09;來實施修改&a…

【Axure高保真原型】標簽樹分類查詢案例

今天和大家分享標簽樹分類查詢案例的原型模版&#xff0c;效果包括&#xff1a; 樹形分類——點擊左側樹形里的箭頭&#xff0c;可以展開或收起子級選項&#xff1b; 查詢表格——點擊標簽樹里的選項&#xff0c;如果是末級選項&#xff0c;可以篩選右側表格用戶標簽&#xf…

容器化部署項目05

一、工作原理 鏡像&#xff1a;容器的模板&#xff0c;包括容器運行時所需的數據 容器&#xff1a;運行中的進程&#xff0c;依賴鏡像運行&#xff0c;鏡像的具現化 鏡像你可以把它看成Python中的類&#xff0c;而容器可以看做是類的實例化對象。 一個類可以有多個對象&#xf…

微信小程序 工作日歷 周計劃日報 修改等提報和狀態展示功能,支持h5,Android ,ios,基于uniapp,適配vue2和vue3

Work-calendar 介紹 &#xff08;底部附鏈接&#xff09; 基于uni-calendar做的定制化開發&#xff0c;主要功能為工作日歷展示和提報組件 ? 1.支持周計劃日報狀態展示且可配置 ? 2.支持農歷展示配置&#xff0c;回到當日&#xff0c;月份切換 ? 3.日歷&#xff0c;周報…

openharmony 鴻蒙 下 利用藍牙API(a2dp模塊-高級音頻,ble模塊-低功耗藍牙等)完成對藍牙音響的控制(藍牙廣播)

1.首先是登錄頁面&#xff08;利用webapi 和本地數據存儲完成登陸操作&#xff09; 2.添加設備&#xff08;利用ble.startBLEScan 和 ble.on("BLEDeviceFind", onReceiveEvent);完成藍牙掃描與顯示&#xff09; 3.藍牙ble連接&#xff08;利用ble.createGattClientDe…

17、邏輯回歸與分類評估 - 從連續到離散的智能判斷

學習目標:理解分類問題的本質和評估方法,掌握邏輯回歸的數學原理和概率解釋,學會二分類和多分類問題的處理方法,熟練使用分類評估指標,理解過擬合和正則化的基本概念。 > 從第16章到第17章:從預測數值到判斷類別 在第16章中,我們學習了線性回歸,解決的是預測連續數…

自動化腳本的核心引擎

自動化腳本作為現代軟件開發與運維的重要工具&#xff0c;其核心引擎承擔著解析指令、調度任務和執行邏輯的關鍵職能。這種引擎本質上是一個輕量級的運行時環境&#xff0c;通過預定義的規則集將人類可讀的腳本語言轉化為機器可執行的原子操作。在持續集成/持續交付&#xff08…

【Vue2 ?】Vue2 入門之旅 · 進階篇(九):Vue2 性能優化

在前幾篇文章中&#xff0c;我們學習了 Vuex 的內部機制以及 Vue Router 的工作原理。本篇將深入探討 Vue2 性能優化&#xff0c;幫助你掌握在開發中提升 Vue 應用性能的方法和技巧。 目錄 性能優化的意義響應式系統優化虛擬 DOM 與渲染優化組件懶加載與按需渲染事件與計算屬性…

【題解】B2600 【深基1.例2】簡單的分蘋果

題目描述 這里有 101010 個蘋果&#xff0c;小 A 拿走了 222 個&#xff0c;Uim 拿走了 444 個&#xff0c;八尾勇拿走剩下的所有的蘋果。我們想知道&#xff1a; 小A 和 Uim 兩個人一共拿走多少蘋果&#xff1f;八尾勇能拿走多少蘋果&#xff1f; 現在需要編寫一個程序&#x…