fix(upload): decodeURIComponent(escape) 우선 한글 파일명 복원, defParamCharset utf8 제거

- lib/decode-upload-filename.js: 전형적 Latin-1 래핑 UTF-8 복원
- multer 경영성과 업로드는 기본 latin1 + 서버에서 decodeUploadFilename
- utf8 defParamCharset는 이중 디코딩으로 á 패턴 등이 날 수 있어 제거

Made-with: Cursor
This commit is contained in:
2026-04-13 18:58:02 +09:00
parent 759557428c
commit 200632f580
3 changed files with 46 additions and 22 deletions

View File

@@ -27,24 +27,7 @@ const {
} = require("./lib/ops-state");
const { fetchOpenGraphImageUrl } = require("./lib/link-preview");
const mgmtPerf = require("./lib/mgmt-perf");
/**
* multipart `filename`이 Latin-1로 잘못 해석된 UTF-8 바이트일 때 복원합니다.
* 이미 한글이 올바른 유니코드로 들어온 경우는 그대로 둡니다.
*/
function decodeMultipartFilename(name) {
if (name == null || typeof name !== "string") return "";
// 이미 한글 등 BMP가 올바르게 들어온 경우(멀티바이트 그대로) 덮어쓰지 않음
if (/[\uAC00-\uD7A3]/.test(name)) return name;
try {
const dec = Buffer.from(name, "latin1").toString("utf8");
// UTF-8이 Latin-1로 잘못 해석된 경우 복원. ASCII-only 파일명은 dec ≈ name.
if (dec && !dec.includes("\uFFFD")) return dec;
} catch (_) {
/* ignore */
}
return name;
}
const { decodeUploadFilename } = require("./lib/decode-upload-filename");
const app = express();
const PORT = process.env.PORT || 8030;
@@ -569,8 +552,7 @@ const mgmtPerfStorage = multer.diskStorage({
const uploadMgmtPerfExcel = multer({
storage: mgmtPerfStorage,
limits: { fileSize: 55 * 1024 * 1024 },
/** Busboy 기본은 latin1; `filename="..."` 안의 UTF-8 바이트를 올바르게 UTF-8 문자열로 씁니다. */
defParamCharset: "utf8",
/** 기본(latin1): `filename`을 바이트→U+00xx 문자열로 두고 `decodeUploadFilename`에서 UTF-8 복원. `utf8`이면 이중 디코딩·깨짐이 날 수 있음. */
fileFilter: (_, file, cb) => {
const ext = path.extname(file.originalname).toLowerCase();
if (ext !== ".xlsx") {
@@ -1263,7 +1245,7 @@ app.post(
const payload = mgmtPerf.buildPayloadFromWorkbook(buf, defaultPayload);
await mgmtPerf.saveUploadAndSnapshot(pgPool, {
userEmail: email,
originalFilename: decodeMultipartFilename(req.file.originalname),
originalFilename: decodeUploadFilename(req.file.originalname),
filePath: req.file.path,
fiscalYear,
quarter,