Angular 4/Java文本文件编码异常:CP1250传输后变为UTF-8如何解决?
解决前端接收文件时编码从CP1250变为UTF-8的问题
咱们一步步拆解问题所在,然后搞定它:
问题根源
你后端代码里犯了一个关键错误:把原始的CP1250字节数组转成了String,然后返回这个String。Spring MVC在返回String类型响应时,会默认用UTF-8编码把字符串重新转成字节输出到响应流里——这一步就已经把编码偷偷换掉了!前端拿到的其实是UTF-8编码的字节,保存后自然就是UTF-8格式的文件。
修复方案
核心思路是:全程保留原始的CP1250字节流,不要做任何字符串转换,同时通过响应头明确告诉前端文件的编码格式。
1. 修改后端代码
直接返回原始的byte[]数组,不要转成String,并在Content-Type里指定正确的编码:
import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import org.springframework.http.MediaType; public ResponseEntity<byte[]> testFile(byte[] textToFile, String filename, String fileExtension) { HttpHeaders headers = new HttpHeaders(); headers.setAccessControlExposeHeaders(Collections.singletonList("Content-Disposition")); // 处理文件名编码,避免特殊字符/中文在不同浏览器的兼容性问题(推荐) String encodedFilename = URLEncoder.encode(filename, StandardCharsets.UTF_8.toString()); headers.set("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFilename); // 明确指定Content-Type为text/plain,编码为Cp1250 headers.setContentType(new MediaType("text", "plain", Charset.forName("Cp1250"))); // 本地保存测试(这部分逻辑不变) try { writeToFileLocal(new String(textToFile, Charset.forName("Cp1250")), filename); } catch (IOException e) { e.printStackTrace(); } // 直接返回原始的byte数组,不做任何字符串转换 return new ResponseEntity<>(textToFile, headers, HttpStatus.OK); }
2. 修改前端代码
确保请求时告诉axios(你用的应该是axios封装的http)不要把响应解析成字符串,直接返回原始的Blob对象:
this.http.post('/api/getFile', params, { headers: headers, responseType: 'blob' // 关键:让axios直接返回Blob,不做编码转换 }) .toPromise().then(response => this.saveToFileSystem(response), (err: HttpErrorResponse) => { if (err.error instanceof Error){ this.pushMSG('ERROR: ' + err.error.message, 'error'); }else { this.pushMSG('Server error, val: ' + err.status + ' , body: ' + err.error,"error"); } }); private saveToFileSystem(response: any) { const contentDispositionHeader: string = response.headers.get('Content-Disposition'); const parts: string[] = contentDispositionHeader.split(';'); // 解析RFC 5987格式的编码文件名 let filename = ''; for (const part of parts) { const trimmedPart = part.trim(); if (trimmedPart.startsWith('filename*=')) { filename = decodeURIComponent(trimmedPart.split('=')[1].replace(/^UTF-8''/, '')); break; } else if (trimmedPart.startsWith('filename=')) { filename = trimmedPart.split('=')[1]; } } // 直接用response.data(已经是正确编码的Blob)保存 saveAs(response.data, filename, true); }
为什么这样能解决问题?
- 后端:直接返回原始的CP1250字节,Spring不会做任何编码转换,同时通过
Content-Type告诉前端这是CP1250编码的文本。 - 前端:通过
responseType: 'blob'让axios直接把响应的字节流包装成Blob对象,跳过字符串解析步骤,保存时自然保留原始编码。
内容的提问来源于stack exchange,提问作者Łukasz Kochanowski
相关产品推荐
相关产品推荐

