后端常用技能:解决java项目前后端传输数据中文出现乱码、问号问题

您所在的位置:网站首页 qt后端响应的方法 后端常用技能:解决java项目前后端传输数据中文出现乱码、问号问题

后端常用技能:解决java项目前后端传输数据中文出现乱码、问号问题

2024-07-05 05:05| 来源: 网络整理| 查看: 265

0. 问题背景

最近做一个解析数据的小工具,本地运行时都正常,发布到服务器上后在导出文件数据时发现中文全部变成了问号,特此记录下问题解决的思路和过程

1. 环境

java 1.8 springboot 2.6.13 额外引入了fastjson,commons-csv等依赖

2. 解决过程 思路1:后端响应体及前端blob对象声明编码格式为utf8

1、首先该问题在本地未发现,服务器上出现了,因此可以明确的是环境编码方式不一致导致的

2、一开始我以为在生成导出数据时出现的问题,项目涉及将导入的文本文件数据解析后导出为csv格式的excel数据

于是首先在导出时,在响应体中声明编码格式为utf8

response.setContentType("application/octet-stream;charset=utf-8");

同时我前端的处理,是将文件流数据转换为blob对象,然后进行文件下载,于是将生成blob对象的地方也声明编码格式

/** * 文件流转换为blob对象进行下载 * @param data 后端返回的文件流数据 * @param filename 文件名 */ function exportBlob(data, filename) { let blob = new Blob([data], {type: "application/octet-stream,charset=UTF-8"}); // 创建一个下载链接 const url = window.URL.createObjectURL(blob); // 创建一个隐藏的元素,并设置其href属性为下载链接 const a = document.createElement('a'); a.href = url; a.download = filename; // 将元素添加到页面中,并模拟点击 document.body.appendChild(a); a.click(); // 完成下载后,移除元素和下载链接 document.body.removeChild(a); window.URL.revokeObjectURL(url); }

3、该方式本地运行正常,发布服务器后仍然有中文为问号的问题。于是继续分析

思路2:application.properties中设置全局编码格式

1、前面已经明确的是:服务器编码格式不一致导致的,于是通过locale指令查询服务器编码格式

在这里插入图片描述 如上图,发现服务器默认配置的编码格式是utf8

2、但结合实际情况,说明服务器编码格式肯定不是utf8,有时因为安装了一些额外的插件会导致服务器的编码格式被更改

同时怀疑数据在输入时就已经乱码了,于是在后端接口,接收输入参数时打印了数据,发现果然解析的中文就是问号,这就说明问题是出在前端传输给后端的数据中文乱码了,而不是后端返回给前端的数据乱码了。

在这里插入图片描述 3、怀疑是前后端的传输编码格式不统一导致的,于是在前端ajax请求中声明数据编码格式UTF-8

$.ajax({ url: 'json/export', type: 'POST', contentType: "application/x-www-form-urlencoded;charset=UTF-8", data: {json: json}, success: function (data, textStatus, xhr) { layer.close(load); if(data.msg != null){ layer.msg(data.msg, {icon: 5}); }else{ exportBlob(data, "json转换输出数据.csv"); layer.msg("导出成功"); } }, error: function (xhr, status, error) { layer.msg("导出失败"); layer.close(load); console.log(xhr); } });

4、同时在后端声明编码格式,因为是springboot项目,所以直接在application.properties中配置:

server.servlet.encoding.enabled=true server.servlet.encoding.force=true server.servlet.encoding.charset=UTF-8

因为我这里springboot版本是2.3+,低版本中应该是

spring.http.encoding.enabled=true spring.http.encoding.force=true spring.http.encoding.charset=UTF-8

该配置可以让服务端在接收和发送数据时使用UTF-8编码

5、再次在服务器上运行,发现还是有中文乱码问题

6、怀疑该配置没生效,于是手写了一个配置类,用于声明编码格式

@Configuration public class WebConfig implements WebMvcConfigurer { @Bean public FilterRegistrationBean characterEncodingFilterRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(new CharacterEncodingFilter()); registration.addInitParameter("encoding", "UTF-8"); registration.addInitParameter("forceEncoding", "true"); registration.addUrlPatterns("/*"); return registration; } private static class CharacterEncodingFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("UTF-8"); response.setContentType("text/html; charset=UTF-8"); chain.doFilter(request, response); } } }

7、服务器上运行,问题还是没解决,说明不是该问题导致

思路3:重新编码传输数据

1、如上我们已经将服务端编码格式设置为utf8了,解析仍然有问题,于是尝试将传入数据二次编码

导入文件解析:

InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.ISO_8859_1);

字符串参数解析:

json = new String(json.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);

2、然后本地运行,发现就出现问题了,本地运行也出现中文乱码了,那么说明编码格式ISO_8859_1肯定不行

3、于是尝试根据环境本身的编码格式去设置

打印了下服务器上的编码格式

log.error("编码:"+ Charset.defaultCharset().name());

服务器打印结果 在这里插入图片描述 这里就可以看到服务器上编码果然不是utf8,于是重新设置编码:

InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.defaultCharset()); json = new String(json.getBytes(Charset.defaultCharset()), StandardCharsets.UTF_8);

4、服务器上运行,依然出现中文乱码

思路4:jvm启动脚本中添加-Dfile.encoding=utf-8

1、目前我们能确定的是服务器的编码格式不是utf8,而是US-ASCII。但在代码中二次编码的形式行不通,这里思路有些阻塞了。可以明确的就是环境编码格式导致的,但是怎么定义环境的编码格式呢? 从项目内部定义的形式似乎都行不通

2、自己思路阻塞的时候一般有两种解决办法: (1)放一放,过几个小时或者第二天再来看,这是思路清空,相对受之前惯性思维的影响较小,一般这时再来看有奇效 (2)与其他人讨论,融合新的思路

3、这里因为想当天把这个问题解决了,于是采取了第二种与同事进行了交流,刚好同事给我说他之前遇到过一种中文乱码的情况,通过在启动脚本里设置-Dfile.encoding=utf-8解决的

于是进行了尝试,在java项目的启动脚本的添加了该配置

JAVA_OPTS="-server -Xms1G -Xmx2G -Xmn256m -Xss1m \ -Dfile.encoding=utf-8 \ -XX:SurvivorRatio=4 -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection \ -XX:CMSInitiatingOccupancyFraction=60 -XX:+PrintGCDateStamps \ -XX:+PrintGCDetails -Xloggc:$LOGS_DIR/gc.log"

4、重启项目,发现中文显示正常了,同时打印的编码格式也变成utf8了。问题解决

5、这里再回过头来看时,发现确实是自己思路陷入局限了,明明知道是环境的问题,却一直期望通过项目内配置解决。

实际上java通过jvm运行,其环境编码问题,自然应该从jvm配置着手。

-Dfile.encoding=utf-8的作用就是设置jvm虚拟机的编码格式,java项目默认字符集是在java虚拟机启动时决定的,依赖于java虚拟机所在的操作系统的区域以及字符集

实际上该配置应该作为我们项目的常用配置,此次也是因为临时做个新工具,忽略了该配置的书写

总结

如上,就是我针对java项目出现中文乱码的问题的解决思路及过程,对比了网上说明的解决方法,发现也基本上涵盖了大多数情况,大家可以参考



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3