项目Controller层为了方便,会统一加上@RestController注解,这样类下面的每一个方法返回值都会自动转换为JSON。 当项目需要返回一个文件对象时,通常会使用ResponseEntity作为返回对象。 在用SpringBoot自带的Jackson时,不知道他内部的机制是如何的,但是如果,一个Controller返回的是一个ResponseEntity对象,这个对象是一个文件流,用于浏览器端下载,使用jackson是没问题的,但在使用fastjson时,它可能默认也会把这个解析为JSON,导致出现异常无法转换。具体报错如下,请问下有没有什么好的解决方案。谢谢!
[alibaba/fastjson]关于Fastjson 转换ResponseEntity 文件流对象时,出现错误
回答
it's a bug
请问这个问题解决了吗
由于springmvc 的convert 根据http的 MediaType 来判断是否要进行处理,支持的MediaType 由构造方法给出。而fastjson 接受的是所有的mediaType,
AbstractHttpMessageConverterprotected AbstractHttpMessageConverter(MediaType supportedMediaType) { setSupportedMediaTypes(Collections.singletonList(supportedMediaType)); }
fastjsonpublic FastJsonHttpMessageConverter() { super(MediaType.ALL); }
jacksonpublic MappingJackson2HttpMessageConverter(ObjectMapper objectMapper) { super(objectMapper, MediaType.APPLICATION_JSON, new MediaType("application", "*+json")); } 问题可能出在这里
+1 没有办法解决吗
我也碰到这个问题了啊,还没有大哥解决下?
这个是因为在返回的时候,默认设置了返回格式,可以在返回方法上替换下,例如:@RequestMapping(value = "/download", produces = "application/octet-stream;charset=UTF-8")
Spring 版本:4.3 fastjson : 1.2.7
问题原因:关键类:AbstractMessageConverterMethodProcessor->writeWithMessageConverters 方法
Spring会获取request的contentType,以及配置的converter支持的contentType,然后找两者都符合的类型,如果是具体的一个contentType,那么就选择该contentType, 随后传给后续的MessageConverter,后续的converter拿到contentType拿到后会查看是否是自己支持的类型,如果是则会进行序列化操作。
HttpServletRequest request = inputMessage.getServletRequest();
List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);
常规默认配置下,Spring 传给Fastjson 的contentType的类型总是text/html的,Fastjson 默认是支持all,所以就会进行序列化,导致出错。
解决办法:最简单的方案是在控制层配置:
@RequestMapping(value = "/download", produces = "application/octet-stream;charset=UTF-8")
这样配置后,在获取 producibleMediaTypes(见上面代码) 的时候就是该指定的类型了,代码逻辑在下面:
protected List<MediaType> getProducibleMediaTypes(HttpServletRequest request, Class<?> valueClass, Type declaredType) {
//获取用户自定的类型
Set<MediaType> mediaTypes = (Set<MediaType>) request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
//如果有则返回
if (!CollectionUtils.isEmpty(mediaTypes)) {
return new ArrayList<MediaType>(mediaTypes);
}
//后面代码省略
}
最后指定
FastJsonHttpMessageConverter 的supportedMediaTypes,不要包含 application/octet-stream;charset=UTF-8
这个bug还没修复吗,springboot2.0遇到同样问题
之前没有详细看文档,今天上来又看了一遍,原来问题已经解决了。感谢测试case