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

2025-11-11 144 views
6

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

回答

3

it's a bug

2

请问这个问题解决了吗

3

由于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")); } 问题可能出在这里

4

+1 没有办法解决吗

4

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

3

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

1
似乎并不完全是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

7

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

4

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