首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在SpringBoot 1.5.10上用Jackson2接收非unicode REST请求

在SpringBoot 1.5.10上用Jackson2接收非unicode REST请求
EN

Stack Overflow用户
提问于 2022-09-14 09:50:48
回答 1查看 18关注 0票数 0

使用Jackson2的Spring假定任何JSON请求都是Unicode,如果编码不是Unicode,则无法容忍非ascii字符。

我发现使用GSON而不是Jackson2可能会有所不同,但我想尝试坚持使用Jackson2。

Jackson2支持任何Java支持的编码,SpringBoot也支持处理任何这些编码,但当协同工作时,它们都假定为Unicode。

SpringBoot将假定所有请求都是UTF-8,除非您禁用该行为:

代码语言:javascript
复制
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-jarwar或者其他方式,它可能会破坏一些东西。

EN

回答 1

Stack Overflow用户

发布于 2022-09-14 13:58:43

我找到了一种通过注册一个新bean来自定义MappingJackson2HttpMessageConverter的方法,所以我创建了这个配置类来注册一个子类的实例,该子类的字符集行为是固定的,当字符集不是Unicode时,创建和使用一个Reader

代码语言:javascript
复制
/**
 * 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());
    }

}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73714838

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档