您的位置:首页 > 编程语言 > Java开发

SpringMVC 上传文件出现 Provisional headers are shown 和 response 数据 无法输出问题

2016-08-18 00:17 936 查看

一、 在项目中使用springMVC 上传文件的时候,在上传文件的大小超过设定的值之后,异常解析器中的异常输出信息无法输出。

上传文件的时候有个文件大小的限制,在超出这个限制之后.会抛出MaxUploadSizeExceededException异常,该异常是spring检查上传文件的信息的时候抛出的,此时还没进入Controller内解析文件的方法中。

产生原因:tomcat7.0.67版本的bug。

解决方式:改变tomcat版本 / 新建一个springmvc 拦截器



没超过限定大小的文件上传成功之后返回的数据:





二、 开发环境

eclipse Mars2

apache-tomcat-7.0.67

mysql 5.5

jersey-client-1.18.jar

jersy-core-1.18.jar 使用jersey进行文件的上传(contos 文件服务器)

三、文件配置

springmvc.xml

<!-- 加载文件上传路径配置文件 解决 @controller 中无法注入配置文件中的属性 -->
<context:property-placeholder location="classpath*:file.properties"/>

<!-- 配置包扫描器 只扫描 @Controller -->
<context:component-scan base-package="com.oa,com.project,com.sso">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />
</context:component-scan>

<!-- 配置注解驱动 -->
<mvc:annotation-driven/>

<!-- 视图解析器 -->
<bean id="viewResolverCommon" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="" />
<property name="suffix" value="" />
</bean>

<!-- 文件上传  -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 单文件上传大小20M-->
<property name="maxUploadSize" value="20971520"/>
<property name="defaultEncoding" value="UTF-8" />
</bean>

<!--  异常处理 -->
<bean id="exceptionResolver" class="com.project.common.exception.ExceptionResolver" />


ExceptionResolver

public class ExceptionResolver implements HandlerExceptionResolver{

private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionResolver.class);

@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {

if(ex instanceof MaxUploadSizeExceededException){
ObjectMapper objectMapper = new ObjectMapper();
response.setContentType("application/json;charset=UTF-8");
try {
PrintWriter writer = response.getWriter();
objectMapper.writeValue(response.getWriter(), LXResult.build(LXStatus.MAX_UPLOAD_SIZE.value(), LXStatus.MAX_UPLOAD_SIZE.display()));
writer.flush();
} catch (Exception ie) {
LOGGER.error("Failed to serialize the object to json for exception handling.", ie);
}
return new ModelAndView();
}
return null;
}}


四、Provisional headers are shown

这个警告的意思是:请求的资源可能会被(扩展/或其他什么机制)屏蔽掉。

为什么会出现这种情况?(参照:https://bz.apache.org/bugzilla/show_bug.cgi?id=57438

之所以会出现这个警告,是因为去获取该资源的请求其实并(还)没有真的发生,所以 Header 里显示的是伪信息,直到服务器真的有响应返回,这里的 Header 信息才会被更新为真实的。不过这一切也可能不会发生,因为该请求可能会被屏蔽或者response多次重定向。

Running a Spring MVC 4.1.4 web application on JDK 7, Ubuntu 14.10 (and Debian Wheezy).

Tested on version 7.0.53 through 7.0.57. The web application works as expected in versions 7.0.53 and 7.0.54. Version 7.0.55 and up display the following issue.

When uploading a large file, larger than the specified maximum, the exception org.springframework.web.multipart.MaxUploadSizeExceededException (caused by a org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException) is caught via an @ExceptionHandler. After logging the exception and resolving some parameters from the inputstream a redirect is performed like this:

return new org.springframework.web.servlet.ModelAndView(“redirect:/error”, new org.springframework.ui.ExtendedModelMap());

I expect that this would generate a HTTP 302 redirect and will trigger a GET request on “/error”. The upload obviously is a POST request and the redirect would perform a GET request. Tomcat version 7.0.54 and .53 indeed do that, but in version 55 and up it remains a POST request. The complete multipart content-type is saved and the whole request is repeated until the server throws an error: (failed) net::ERR_CONNECTION_RESET.

Provisional headers:

Request URL:https://localhost:8443/import/ratings

Request Headers

Provisional headers are shown

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8

Content-Type:multipart/form-data; boundary=—-WebKitFormBoundaryNT3MUmtXDpFSSCLy

Origin:https://localhost:8443

Referer:https://localhost:8443/import/ratings

User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36

Request Payload

——WebKitFormBoundaryNT3MUmtXDpFSSCLy

Content-Disposition: form-data; name=”commandName”

importRatingsCommand

——WebKitFormBoundaryNT3MUmtXDpFSSCLy

Content-Disposition: form-data; name=”ratings”; filename=”file.pdf”

Content-Type: application/pdf

这是tomcat版本造成的bug.使得MaxUploadSizeExceededException进行死循环。就是302的重复重定向。

五。既然已经知道问题的产生原因。那么就有以下两种解决方案

5.1 简单粗暴–直接更换tomcat版本(不更改异常解析器和springmvc配置)

apache-tomcat-7.0.67 (不可用)

apache-tomcat-7.0.39 (可用)

apache-tomcat-7.0.70 (可用)
其他版本没有测试,不知道是否存在此bug。

springmvc.xml

!-- 文件上传  -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 单文件上传大小20M-->
<property name="maxUploadSize" value="20971520"/>
<property name="defaultEncoding" value="UTF-8" />
</bean>

<!--  异常处理 -->
<bean id="exceptionResolver" class="com.project.common.exception.ExceptionResolver" />


异常解析类ExceptionResolver和前面的保持一致(由于前后端数据使用json交互,故返回的ModelAndView 为null,不需要视图的跳转)。

5.2 退而求其次–使用springMVC拦截器(必须把maxUploadSize 设置大一点,让它不会抛异常出来)

新建一个拦截器专门用来控制上传大小,输出异常之后需要json输出的数据。(如果不是json交互的,可以直接抛出异常或者处理,都是可以的)

springmvc.xml

<!--多文件上传部分 (不需要配置 异常解析器)-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 单文件上传大小20M ,这里需要设置的大一点,避免在拦截器之前出现异常,很重要,这里是400M-->
<!--maxUploadSize 使用拦截器时可以不用设置-->
<property name="maxUploadSize" value="409715200"/>
<property name="defaultEncoding" value="UTF-8" />
</bean>

<!--注册拦截器 方式一(上传文件的大小写在配置文件中) 推荐-->
<mvc:interceptors>
<mvc:interceptor>
<!--此处只拦截文件上传的请求-->
<mvc:mapping path="/file/fileUpload.do"/>
<bean class="com.sso.interceptor.FileInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>

<!--注册拦截器 方式二(上传文件的大小在这里注入进来)不推荐-->
<!--<mvc:interceptors>
<mvc:interceptor>
<!--此处只拦截文件上传的请求-->
<mvc:mapping path="/file/fileUpload.do"/>
<bean class="com.sso.interceptor.FileInterceptor">
<property name="MAX_UPLOAD_SIZE" value="20971520"/>
</bean>
</mvc:interceptor>
</mvc:interceptors>-->


FileInterceptor.java

/**
* @ClassName: FileInterceptor
* @Description: 上传附件大小拦截器
* @author liudongdong
* @date 2016年8月17日 下午2:47:39
* @version V1.0
*/
public class FileInterceptor implements HandlerInterceptor{

//配置文件中读取上传文件的大小(20M)[方式一] 可以使用其他方式
@Value("${MAX_UPLOAD_SIZE}")
private long MAX_UPLOAD_SIZE;

/**
*//拦截器使用方式二时,这里使用set方法
*private long MAX_UPLOAD_SIZE;
*
*public void setMAX_UPLOAD_SIZE(long mAX_UPLOAD_SIZE) {
*  thisMAX_UPLOAD_SIZE = mAX_UPLOAD_SIZE;
*}
*/

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

//判断是否是多文件上传的请求
if (request != null && ServletFileUpload.isMultipartContent(request)) {
ServletRequestContext requestContext = new ServletRequestContext(request);
long requsetSize = requestContext.getContentLength();
if (requsetSize > MAX_UPLOAD_SIZE) {
ObjectMapper mapper = new ObjectMapper();
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
PrintWriter writer = response.getWriter();
//json输出提示信息
mapper.writeValue(writer, LXResult.build(LXStatus.MAX_UPLOAD_SIZE.value(), LXStatus.MAX_UPLOAD_SIZE.display()));
writer.flush();
return false;
}
}
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv)
throws Exception {
// TODO Auto-generated method stub
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}


测试成功(存在bug的tomcat7.0.67,使用拦截器)



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring mvc 异常
相关文章推荐