美文网首页Spring Boot
Springboot解决header中的中文编码问题

Springboot解决header中的中文编码问题

作者: 一曲畔上 | 来源:发表于2019-10-28 10:12 被阅读0次

    1,http的header中不能直接传中文变量,我们添加到header中的中文,需要encoder转码;
    我们就用常规的utf8编码转码;比如我们设定一个header中的参数name="小明",那我们只能是用
    header.add("name", URLEncoder.encode("小明", "utf8"));
    也就是header.add("name", "%E5%B0%8F%E6%98%8E");
    2,在Springboot接收端,使用@RequestHeader(value = "name")接收到的是"%E5%B0%8F%E6%98%8E",而不是"小明"。当然了,也可以用传统方式,对于接收到的参数进行decoder,但是如果header参数比较多的情况下,这个方式就不那么友好了。
    3,今天我要介绍的是基于Springboot的特性的一种解决方案,使用Springboot的转换器GenericConverter!
    步骤如下:
    3.1,实现接口GenericConverter

    public class StringDecoderForHeaderConverter implements GenericConverter {
        private Logger logger = LoggerFactory.getLogger(StringDecoderForHeaderConverter.class);
        
        private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
        private static final String NO_NAME = "NO_NAME";
        
        private Charset charset;
        
        public StringDecoderForHeaderConverter(@Nullable Charset charset) {
            this.charset = charset;
            if (this.charset == null) {
                this.charset = DEFAULT_CHARSET;
            }
        }
        
        /**
         * +返回编码值
         * @return charset
         */
        public Charset getCharset() {
            return charset;
        }
        
        /**
         * +设置编码值
         * @param charset 编码值
         */
        public void setCharset(Charset charset) {
            this.charset = charset;
            
            if (this.charset == null) {
                this.charset = DEFAULT_CHARSET;
            }
        }
        
        @Override
        public Set<ConvertiblePair> getConvertibleTypes() {
            return Collections.singleton(new ConvertiblePair(String.class, String.class));
        }
    
        @Override
        public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
            if (ObjectUtils.isEmpty(source)) {
                return source;
            }
            
            String name = needDecoder(source, targetType);
            if (name != null) {
                return convert(source.toString(), name);
            }
            
            return source;
        }
        
        /**
         * +是否需要解码
         * @param source 待处理的值
         * @param targetType 类型
         * @return 非null:需要解码;null:无需解码
         */
        private String needDecoder(Object source, TypeDescriptor targetType) {
            RequestHeader requestHeader = targetType.getAnnotation(RequestHeader.class);
            Class<?> type = targetType.getType();
            if (requestHeader != null && type == String.class) {
                if (source.toString().indexOf("%") >= 0) {
                    String name = requestHeader.name();
                    if (name == null || name.equals("")) {
                        name = requestHeader.value();
                    }
                    if (name == null || name.equals("")) {
                        name = NO_NAME;
                    }
                    
                    return name;
                }
            }
            
            return null;
        }
        
        /**
         * +结果解码
         * @param source 待解码的结果
         * @param name 参数名称
         * @return 解码后的结果
         */
        private String convert(final String source, final String name) {
            if (logger.isDebugEnabled()) {
                logger.debug("Begin convert[" + source + "] for RequestHeader[" + name + "].");
            }
            String _result = null;
            try {
                _result = URLDecoder.decode(source, this.charset.name());
                if (logger.isDebugEnabled()) {
                    logger.debug("Success convert[" + source + ", " + _result + "] for RequestHeader[" + name + "].");
                }
                
                return _result;
            } catch(Exception e) {
                logger.warn("Fail convert[" + source + "] for RequestHeader[" + name + "]!", e);
            }
            
            return source;
        }
    }
    

    代码不难理解,就是对应带有@RequestHeader注解的参数如果参数值中有"%",说明可能有被encoder的可能,那么我们需要decoder。
    3.2,注册该bean

    @Configuration(proxyBeanMethods = false)
    @EnableConfigurationProperties({ HttpProperties.class })
    @Import({ WebMvcAutoConfiguration.class })
    @ComponentScan(
            value = "com.beyonds.phoenix.sun.web",
            includeFilters = {
                    @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)
            })
    public class WebMvcConfiguration implements WebMvcConfigurer {
        /**
         * +定义HttpClient
         * @return HttpClient
         */
        @Bean
        @ConfigurationProperties(prefix = "feign.httpclient")
        public HttpClientBuilder apacheHttpClientBuilder() {
            return HttpClientBuilder.create();
        }
        
        /**
         * +自定义输入的日期格式
         * +覆盖spring.mvc.date-format
         * @return 日期格式转换器
         */
        @Bean
        public StringDateConverter dateConverter() {
            return new StringDateConverter();
        }
        
        /**
         * +对于header中的中文字进行解码
         * @return 转换结果
         */
        @Bean
        public StringDecoderForHeaderConverter stringHeaderConverter(HttpProperties httpProperties) {
            return new StringDecoderForHeaderConverter(httpProperties.getEncoding().getCharset());
        }
    }
    

    3.3,配置编码参数,利用HttpProperties

    spring: 
      application: 
        name: phoenix-sun
      http: 
        converters: 
          preferred-json-mapper: jackson
        encoding:
          enabled: true
          charset: UTF-8
          force: true
    

    3.4,这样就ok了,无需对某个header去单独处理了。
    4,完整的代码示例请参照代码示例或者代码示例

    相关文章

      网友评论

        本文标题:Springboot解决header中的中文编码问题

        本文链接:https://www.haomeiwen.com/subject/zqpvvctx.html