Spring boot 字符集编码

Posted 417xiaoliu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring boot 字符集编码相关的知识,希望对你有一定的参考价值。

来源

近一段在开发接口平台,使用spring boot 开发,总体来说还是蛮顺利;
接口平台不可避免的让别人调用服务,也会去调用其它的外部接口;
突然有一天,某个服务商回调信息中出现了乱码,形如:??????,打破了宁静

分析过程

向服务商确认,该接口传递的参数使用GBK编码,WHT??现在还有用GBK的,不是用UTF8编码么?
马上确认我的程序编码:

server.tomcat.uri-encoding 未设置
http.encoding.charset: UTF-8
http.encoding.force-request: true

可以看到uri的配置未定义,搜索文档说明spring boot默认使用UTF8编码
下面两个是定义HTTP的字符集,用来设置request与response的字符集;
跟踪源码,发现这个字符参数会在CharacterEncodingFilter中用到,核心的方法是使用:request.setCharacterEncoding("UTF-8"),并且是一个全局的内容

解决过程

  1. 将得到的乱码用UTF-8编码再用GBK解码,如下代码,得到结果为:锟斤拷值失锟斤拷
    new String(source.getBytes("UTF-8"),"GBK"), 通过查资料得知,以GBK编码->UTF-8解码(出现乱码)->UTF-8编码(这步由于UTF8编码的特殊性,会增加部分头信息)->GBK解码(由于加了特殊部分,所以造成不可逆的结果)

  2. 在方法中调用request.getCharacterEncoding("UTF-8")无效,查询rquest的这个方法说明,只有在获取参数之前调用这个方法才有效,但在此之前spring 已帮我们做了很多事情,所以在这里无效;

  3. 自已写Filte来实现设置,但不知什么原因,还是无效

  4. 继承CharacterEncodingFilter,对特定url做特殊处理,结果是自定义的encoding生效了,原先的UTF8的 encodingFilter失效了,就算修改自己的Bean名字还不行

  5. 修改自定义EncodingFilter,实现多字符集的处理:
    定义encodingFilter:

public class MutiCharacterEncodingFilter extends CharacterEncodingFilter implements Ordered{

    //最高优先级
    private int order = Integer.MIN_VALUE;


    private List<String> mutiUrls = new ArrayList();

    private String mutiCharset =  "GBK";


    public List<String> getMutiUrls() {
        return mutiUrls;
    }

    public void setMutiUrls(List<String> mutiUrls) {
        this.mutiUrls = mutiUrls;
    }

    public String getMutiCharset() {
        return mutiCharset;
    }

    public void setMutiCharset(String mutiCharset) {
        this.mutiCharset = mutiCharset;
    }


    /**
     *  @param charset
     * @param mutiCharset
     * @param mutiUrls
     * @param forceRequest
     * @param forceResponse
     */
    public MutiCharacterEncodingFilter(String charset, String mutiCharset , List<String> mutiUrls, boolean forceRequest, boolean forceResponse) {
        super(charset,forceRequest,forceResponse);
        this.mutiUrls = mutiUrls;
        this.mutiCharset = mutiCharset;

    }

    public MutiCharacterEncodingFilter() {
        super();
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        String path = request.getRequestURI();

        //如果是这个链接 执行mutyEncoding方法
        if(PathMatcherUtil.matchAny(mutiUrls,path)){
            if (mutiCharset != null) {
                if (isForceRequestEncoding() || request.getCharacterEncoding() == null) {
                    request.setCharacterEncoding(mutiCharset);
                }
                if (isForceResponseEncoding()) {
                    response.setCharacterEncoding(mutiCharset);
                }
            }
            filterChain.doFilter(request,response);
            return ;
        }

        //否则 使用默认方法
        super.doFilterInternal(request,response,filterChain);

    }


    @Override
    public int getOrder() {
        return order;
    }

在配置中设置相应内容:

  http:
    encoding:
      charset: UTF-8
      force-request: true
      force-response: false
      mutiCharset: GBK
      mutiUrls:
        - /notify/test

在config中生成实例

    //第一种字符集
    @Value(value = "${spring.http.encoding.charset}")
    private String charset;
    //是否强制应用到request
    @Value(value = "${spring.http.encoding.force-request}")
    private boolean forceRequest;
    //是否强制设置到response
    @Value(value = "${spring.http.encoding.force-response}")
    private boolean forceResponse;



    /**
     * 自定义HTTP字符集 默认使用charset字符集 在特定情况下使用第二字符集 用于欧飞回调GBK编码
     * 仅对POST中的表单参数有效 对于URI中的参数无效 只能去修改tomcat的字符集编码 应该不致于做的这么绝吧
     * @return
     */
    @Bean()
    @ConfigurationProperties(prefix = "spring.http.encoding")
    @ConfigurationPropertiesBinding
    public MutiCharacterEncodingFilter mutiCharacterEncodingFilter(){
        MutiCharacterEncodingFilter encodingFilter = new MutiCharacterEncodingFilter();
        encodingFilter.setEncoding(charset);
        encodingFilter.setForceRequestEncoding(forceRequest);
        encodingFilter.setForceResponseEncoding(forceResponse);
        return encodingFilter;
    }

到此问题解决,可以接收GKB编码的内容;

但同时也有缺陷,只适用于body的内容,不适用于链接到URL后面的请求参数,如果要支持,只能修改tomcat-uri-encoding为UTF-8,希望对大家有帮助.








以上是关于Spring boot 字符集编码的主要内容,如果未能解决你的问题,请参考以下文章

Spring boot:thymeleaf 没有正确渲染片段

spring boot + thymeleaf 无法正确编码 POST 中的 UTF-8 字符

解决spring-boot启动中碰到的问题:Cannot determine embedded database driver class for database type NONE(转)(代码片段

一张图,理顺 Spring Boot应用在启动阶段执行代码的几种方式

一张图帮你记忆,Spring Boot 应用在启动阶段执行代码的几种方式

一张图,理顺 Spring Boot应用在启动阶段执行代码的几种方式