fastjson 关于Fastjson 转换ResponseEntity 文件流对象时,出现错误

2eafrhcq  于 2021-11-27  发布在  Java
关注(0)|答案(9)|浏览(600)

项目Controller层为了方便,会统一加上@RestController注解,这样类下面的每一个方法返回值都会自动转换为JSON。
当项目需要返回一个文件对象时,通常会使用ResponseEntity作为返回对象。
在用SpringBoot自带的Jackson时,不知道他内部的机制是如何的,但是如果,一个Controller返回的是一个ResponseEntity对象,这个对象是一个文件流,用于浏览器端下载,使用jackson是没问题的,但在使用fastjson时,它可能默认也会把这个解析为JSON,导致出现异常无法转换。具体报错如下,请问下有没有什么好的解决方案。谢谢!

nkkqxpd9

nkkqxpd92#

请问这个问题解决了吗

v8wbuo2f

v8wbuo2f3#

由于springmvc 的convert 根据http的 MediaType 来判断是否要进行处理,支持的MediaType 由构造方法给出。而fastjson 接受的是所有的mediaType,

AbstractHttpMessageConverter

protected AbstractHttpMessageConverter(MediaType supportedMediaType) {
setSupportedMediaTypes(Collections.singletonList(supportedMediaType));
}
##fastjson
public FastJsonHttpMessageConverter() {
super(MediaType.ALL);
}
##jackson
public MappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper, MediaType.APPLICATION_JSON, new MediaType("application", "*+json"));
}
问题可能出在这里

imzjd6km

imzjd6km4#

+1 没有办法解决吗

tpgth1q7

tpgth1q75#

我也碰到这个问题了啊,还没有大哥解决下?

rn0zuynd

rn0zuynd6#

这个是因为在返回的时候,默认设置了返回格式,可以在返回方法上替换下,例如:@RequestMapping(value = "/download", produces = "application/octet-stream;charset=UTF-8")

zour9fqk

zour9fqk7#

似乎并不完全是Fastjson 的问题

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

but5z9lq

but5z9lq8#

这个bug还没修复吗,springboot2.0遇到同样问题

j1dl9f46

j1dl9f469#

之前没有详细看文档,今天上来又看了一遍,原来问题已经解决了。感谢测试case

相关问题