NestJS中如何正确传递文件名?西里尔文名称丢失问题排查
解决西里尔文文件名上传后丢失的问题
前端(Expo)调整
- 移除手动设置的
Content-Type头部:axios会自动为FormData生成包含正确边界的multipart/form-data头部,手动设置会破坏边界解析逻辑,导致后端无法正确读取文件名。修改代码如下:export const updateTaskApi = async ( id: string, taskData: TTask, files: TDataFilePicker[] | null, ) => { const headers = await createHeaders(); // 删除该行:headers['Content-Type'] = 'multipart/form-data'; console.log('headers', headers); const formData = new FormData(); formData.append('taskData', JSON.stringify(taskData)); if (files) { files.forEach((file) => { console.log('前端文件名:', file.filePickerName); // 确认文件名是否完整 formData.append( 'files', { uri: file.filePickerUri, type: file.filePickerType, name: file.filePickerName, // 仅保留name字段,移除冗余的fileName } as any, ); }); } return await axios.put(`${basicUrl}/tasks`, formData, { withCredentials: true, headers, }); };
后端(NestJS/Multer)调整
Multer默认使用latin1编码解析文件名,无法处理西里尔文等非ASCII字符,需强制指定UTF-8编码:
配置Multer拦截器的编码选项:
import { FilesInterceptor } from '@nestjs/platform-express'; import multer from 'multer'; @Put() @HttpCode(HttpStatus.OK) @UseInterceptors(FilesInterceptor('files', undefined, { // 核心:设置文件名解析编码为UTF-8 parserOptions: { encoding: 'utf8' }, // 可选:若需保存文件,配置存储路径 dest: './temp/uploads' })) async updateTask( @Body() body: TaskFormData, @Req() request: Request, @UploadedFiles() files?: Array<Express.Multer.File>, ) { await verifyAuthorization(request); console.log('处理后的文件:', files); // 后续业务逻辑保持不变 }手动解码文件名(备选方案):
如果上述配置无效,可从请求头中手动提取并解码UTF-8格式的文件名:// 辅助函数:从Content-Disposition头中提取UTF-8编码的文件名 function getUtf8Filename(contentDisposition: string): string | null { const filenameMatch = contentDisposition.match(/filename\*=UTF-8''([\w\-\.а-яА-Я]+)/); if (filenameMatch) { return decodeURIComponent(filenameMatch[1]); } return null; } // 在控制器中应用 async updateTask( @Body() body: TaskFormData, @Req() request: Request, @UploadedFiles() files?: Array<Express.Multer.File>, ) { await verifyAuthorization(request); // 修正文件名 if (files) { files.forEach(file => { const contentDisposition = request.headers['content-disposition'] as string; const utf8Filename = getUtf8Filename(contentDisposition); if (utf8Filename) { file.originalname = utf8Filename; } }); } console.log('修正后的文件名:', files?.map(f => f.originalname)); // 后续业务逻辑保持不变 }
验证步骤
- 前端打印
file.filePickerName,确认原始文件名完整(如Аватар.jpg)。 - 后端查看请求头的
content-disposition字段,确认包含filename*=UTF-8''%D0%90%D0%B2%D0%B0%D1%82%D0%B0%D1%80.jpg格式的编码文件名。 - 检查后端输出的
originalname字段,确认西里尔文前缀已恢复。
内容的提问来源于stack exchange,提问作者juniorQuestion
相关产品推荐
相关产品推荐

