Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
stjava opened this issue Jan 10, 2018 · 9 comments
Open

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

stjava opened this issue Jan 10, 2018 · 9 comments

Comments

@stjava
Copy link

stjava commented Jan 10, 2018

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

@kimmking
Copy link
Contributor

it's a bug

@wangkeshan9538
Copy link

请问这个问题解决了吗

@wangkeshan9538
Copy link

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

@CowSmiles
Copy link

+1 没有办法解决吗

@catchUheart
Copy link

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

@iqeq00
Copy link

iqeq00 commented Nov 7, 2018

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

@ztgreat
Copy link

ztgreat commented Nov 7, 2018

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

wenshao added a commit that referenced this issue Mar 1, 2019
@ygp1026
Copy link

ygp1026 commented Dec 8, 2019

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

@ygp1026
Copy link

ygp1026 commented Jan 21, 2020

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants