Spring Boot+Angular下载阿拉伯文件名被替换为下划线问题求助
问题描述
本地开发基于Spring Boot与Angular 14的文件上传下载项目,出现以下异常:
- 含阿拉伯字符的文件上传后可正常存储至本地,但下载时文件名中的阿拉伯字符会被替换为下划线。
- 若移除
Content-Disposition头中的文件名参数,文件能以阿拉伯原文件名下载,但除.doc格式外,.txt、.jpg、.png等文件的扩展名会被自动改为.htm。
前端代码
<div class="card mt-3"> <div class="card-header">لائحة المرفقات</div> <ul class="list-group list-group-flush" *ngFor="let file of fileInfos | async"> <li class="list-group-item"> <a href="{{ file.url }}" target="_blank" download="{{ file.name }}">{{ file.name }}</a> </li> </ul> </div>
后端原代码
@GetMapping("/files/{fileRef}/{filename}") public ResponseEntity<Resource> getFile( @PathVariable String filename,@PathVariable String fileRef) { Resource file = storageService.load(fileRef+'/'+filename); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"").body(file); }
已尝试无效的方法
- 强制设置
Content-Type为application/x-www-form-urlencoded; charset=utf-8 - 使用
new String(file.getFilename().getBytes(),Charset.forName("UTF-8"))重新编码文件名
解决方法
核心问题是HTTP响应头Content-Disposition中的非ASCII字符未按标准编码,导致浏览器解析失败;同时错误的Content-Type设置引发扩展名异常。
后端修正:使用标准编码处理文件名
Spring 5及以上版本提供的ContentDisposition类可自动生成兼容RFC 5987的编码格式,同时适配不同浏览器的解析规则:
@GetMapping("/files/{fileRef}/{filename}") public ResponseEntity<Resource> getFile(@PathVariable String filename, @PathVariable String fileRef) { Resource file = storageService.load(fileRef + '/' + filename); String originalFilename = file.getFilename(); // 构建符合标准的Content-Disposition头 ContentDisposition contentDisposition = ContentDisposition.builder("attachment") .filename(originalFilename, StandardCharsets.UTF_8) .build(); // 自动识别文件MIME类型,避免扩展名被篡改 MediaType mediaType = MediaTypeFactory.getMediaType(file) .orElse(MediaType.APPLICATION_OCTET_STREAM); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition.toString()) .contentType(mediaType) .body(file); }
关键细节:
ContentDisposition的作用:自动生成filename(兼容旧浏览器)和filename*=UTF-8''编码后的文件名两个参数,确保阿拉伯字符能被正确解析。- 正确设置
Content-Type:通过MediaTypeFactory根据文件自动匹配MIME类型,避免浏览器因无法识别类型而修改扩展名。
前端优化(可选)
使用Angular属性绑定替代插值表达式,减少编码风险:
<li class="list-group-item"> <a [href]="file.url" target="_blank" [download]="file.name">{{ file.name }}</a> </li>
内容的提问来源于stack exchange,提问作者hamzaP
相关产品推荐
相关产品推荐

