Springboot解决header中的中文编码问题
2019-10-28 本文已影响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