使用Jackson2的Spring假定任何JSON请求都是Unicode,如果编码不是Unicode,则无法容忍非ascii字符。
我发现使用GSON而不是Jackson2可能会有所不同,但我想尝试坚持使用Jackson2。
Jackson2支持任何Java支持的编码,SpringBoot也支持处理任何这些编码,但当协同工作时,它们都假定为Unicode。
SpringBoot将假定所有请求都是UTF-8,除非您禁用该行为:
server.servlet.encoding.force-request=false但是,方法org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(Type, Class<?>, HttpInputMessage)不能访问请求,但它可以访问HttpInputMessage中的头,但在SpringBoot 1.5.10上不能访问。
它在没有编码规范的情况下将InputStream传递给Jackson2,并假设它是Unicode。
解决方案是创建一个InputStreamReader,其中包含可以在标头中找到的编码。
这似乎是当前版本的SpringBoot中的实际行为,但我不知道是否可以在SpringBoot 1.5.10中覆盖旧版本。
我可以扩展类MappingJackson2HttpMessageConverter,但我不知道如何使SpringBoot使用新的转换器,而不是Jackson2的默认转换器。
我可以使用自定义版本来处理类路径来覆盖整个AbstractJackson2HttpMessageConverter,但我不喜欢这样做,因为如果我制作一个fat-jar或war或者其他方式,它可能会破坏一些东西。
发布于 2022-09-14 13:58:43
我找到了一种通过注册一个新bean来自定义MappingJackson2HttpMessageConverter的方法,所以我创建了这个配置类来注册一个子类的实例,该子类的字符集行为是固定的,当字符集不是Unicode时,创建和使用一个Reader。
/**
* Configuration class to override the default
* MappingJackson2HttpMessageConverter of SpringBoot 1.5 that fails to use the
* request charset to parse JSON post bodies.
*/
@Configuration
public class Jackson2CharsetSupportConfig {
private final class MappingJackson2HttpMessageConverterExtension extends MappingJackson2HttpMessageConverter {
private MappingJackson2HttpMessageConverterExtension(ObjectMapper objectMapper) {
super(objectMapper);
}
@Override
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
JavaType javaType = getJavaType(clazz, null);
return readJavaType(javaType, inputMessage);
}
@Override
public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
JavaType javaType = getJavaType(type, contextClass);
return readJavaType(javaType, inputMessage);
}
private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) {
try {
MediaType contentType = inputMessage.getHeaders().getContentType();
Charset charset = getCharset(contentType);
boolean unicode = charset.name().toUpperCase().startsWith("UTF-");
if (inputMessage instanceof MappingJacksonInputMessage) {
Class<?> deserializationView = ((MappingJacksonInputMessage) inputMessage).getDeserializationView();
if (deserializationView != null) {
if (unicode) {
return this.objectMapper.readerWithView(deserializationView).forType(javaType).
readValue(inputMessage.getBody());
} else {
return this.objectMapper.readerWithView(deserializationView).forType(javaType).
readValue(asReader(inputMessage.getBody(), charset));
}
}
}
if (unicode) {
return this.objectMapper.readValue(inputMessage.getBody(), javaType);
} else {
return this.objectMapper.readValue(asReader(inputMessage.getBody(), charset), javaType);
}
}
catch (JsonProcessingException ex) {
throw new HttpMessageNotReadableException("JSON parse error: " + ex.getOriginalMessage(), ex);
}
catch (IOException ex) {
throw new HttpMessageNotReadableException("I/O error while reading input message", ex);
}
}
protected Charset getCharset(MediaType contentType) {
if (contentType != null && contentType.getCharset() != null) {
return contentType.getCharset();
}
else {
return StandardCharsets.UTF_8;
}
}
protected Reader asReader(InputStream is, Charset charset) {
return new InputStreamReader(is, charset);
}
}
@Autowired
private GenericWebApplicationContext webApplicationContext;
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
return new MappingJackson2HttpMessageConverterExtension(Jackson2ObjectMapperBuilder.json().applicationContext(webApplicationContext).build());
}
}https://stackoverflow.com/questions/73714838
复制相似问题