源代码:

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String uri = request.getRequestURI();
if(pathMatcher.match("/", uri)) {
System.err.println("跳转");
response.sendRedirect("/swagger-ui.html");
// return false; // 如果此处不返回false, 则springMvc会继续对“/”路径进行处理,就会出现多次返回响应的错误。 }
return true;
}

注:此处对“/”路径的访问返回404.

DispatcherServlet.doDispatch()中对拦截 器的preHandle进行调用:

// 如果拦截器的PreHandle返回false,则此处直接返回退出方法。
if(!mappedHandler.applyPreHandle(request,response)){
return ;
}
// Actually invoke the handler. 调用处理器
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 由此处可知如果拦截器的preHandle方法返回false则不会调用处理器(控制器类的方法)

mappedHandler是一个HandlerExcutionChain对象由HandlerMapping返回,HandlerExcutionChain包含一个Handler(处理器对象)和拦截器数组,通过applyPreHandle(request,response)方法会对拦截器数组中的每一个拦截器的preHandle进行调用。

// HandlerExcutionChain类
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}

在本例中出现上述错误的原因:

  1. 拦截器拦截了对“/”路径的请求,并且调用response.sendRedirect("/swagger-ui.html")返回了响应。由于拦截器没有返回false,所以SpringMVC会继续对“/”路径进行处理。

  2. 在没有找到“/”对应的处理器时,SpringMVC默认会使用ResourceHttpRequestHandler进行请求处理。ResourceHttpRequestHandler在进行请求处理时会进行404检查,如果路径或资源不存在则会调用response.sendError(HttpServletResponse.SC_NOT_FOUND);源码如下:

    // ResourceHttpRequestHandler中进行404检查
    // For very general mappings (e.g. "/") we need to check 404 first
    Resource resource = getResource(request);
    if (resource == null) {
    logger.debug("Resource not found");
    response.sendError(HttpServletResponse.SC_NOT_FOUND);
    return;
    }
  3. 由2可知,如果资源不存在就会调用response.sendError(HttpServletResponse.SC_NOT_FOUND);而在拦截器中已经调用response.sendRedirect("/swagger-ui.html")对响应进行了返回,所以就会出现多次返回响应的错误。

对于上述问题的解决办法是在response.sendRedirect("/swagger-ui.html");后返回false,或者将拦截路径由“/”改为response.sendError(HttpServletResponse.SC_NOT_FOUND);后的路径(在此处为“/error”)。

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String uri = request.getRequestURI();
if(pathMatcher.match("/", uri)) { response.sendRedirect("/swagger-ui.html");
return false; // 如果此处不返回false, 则springMvc会继续对“/”路径进行处理,就会出现多次返回响应的错误。 }
return true;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String uri = request.getRequestURI();
if(pathMatcher.match("/error", uri)) { response.sendRedirect("/swagger-ui.html"); }
return true;
}

下面是SpringMVC处理"/api/test/error"请求时打印的部分日志(/api/test/error没有对应的处理器,即该路径不存在,报404错误):

注:自定义的拦截器是在映射结束后才执行的。

// 请求路径
2019-02-20 14:55:57.086 DEBUG 2676 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : GET "/api/test/error", parameters={}
// 处理器映射器和请求路径对应的处理器
2019-02-20 14:55:57.092 DEBUG 2676 --- [nio-8080-exec-1] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped to ResourceHttpRequestHandler ["classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/"]
// 处理结果
2019-02-20 14:55:57.094 DEBUG 2676 --- [nio-8080-exec-1] o.s.w.s.r.ResourceHttpRequestHandler : Resource not found
2019-02-20 14:55:57.095 DEBUG 2676 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed 404 NOT_FOUND

下面是SpringMVC处理“/api/test/error1”请求时打印的部分日志(/api/test/error1对应的处理器在org.lwt.controller.RoleController类下的.ErrorTest()方法):

// 请求路径
2019-02-20 15:13:23.860 DEBUG 2676 --- [nio-8080-exec-5] o.s.web.servlet.DispatcherServlet : GET "/api/test/error1", parameters={}
// 处理器映射器和请求路径对应的处理器
2019-02-20 15:13:23.861 DEBUG 2676 --- [nio-8080-exec-5] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public org.lwt.vo.Result<java.lang.String> org.lwt.controller.RoleController.ErrorTest() 拦截器调用
// 处理结果
2019-02-20 15:13:23.865 DEBUG 2676 --- [nio-8080-exec-5] o.s.web.servlet.DispatcherServlet : Failed to complete request: org.joda.time.IllegalInstantException: 自己抛出错误 2019-02-20 15:13:23.867 ERROR 2676 --- [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.joda.time.IllegalInstantException: 自己抛出错误] with root cause
// RoleController类
@RestController
@RequestMapping("/api")
@Api
public class RoleController {
// /api/test/error1对应的处理器
@GetMapping("/test/error1")
public Result<String> ErrorTest(){
throw new IllegalInstantException("自己抛出错误");
// return Result.success("多参数传递");
}
}

下面是SpringMVC处理“/api/test/error1”请求时打印的部分日志(/api/test/error1对应的处理器在org.lwt.controller.RoleController类下的.ErrorTest()方法):

此处和上一次调用的区别是此次调用处理器没有报错:

// 请求路径
2019-02-20 15:21:31.440 DEBUG 8252 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : GET "/api/test/error1", parameters={}
// 处理器映射器和请求路径对应的处理器
2019-02-20 15:21:31.444 DEBUG 8252 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public org.lwt.vo.Result<java.lang.String> org.lwt.controller.RoleController.ErrorTest() 拦截器中的uri: /api/test/error1 // 处理结果
2019-02-20 15:21:31.473 DEBUG 8252 --- [nio-8080-exec-1] m.m.a.RequestResponseBodyMethodProcessor : Using 'application/json;q=0.8', given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, */*;q=0.8] and supported [application/json, application/*+json, application/json, application/*+json] 2019-02-20 15:21:31.473 DEBUG 8252 --- [nio-8080-exec-1] m.m.a.RequestResponseBodyMethodProcessor : Writing [org.lwt.vo.Result@334348d5] 2019-02-20 15:21:31.486 DEBUG 8252 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed 200 OK

java.lang.IllegalStateException: Cannot call sendError() after the response has been committed解读的更多相关文章

  1. 报错:java.lang.IllegalStateException: Cannot call sendError() after the response has been committed(待解答)

    严重: Servlet.service() for servlet [default] in context with path [/20161101-struts2-1] threw excepti ...

  2. java.lang.IllegalStateException: Cannot call sendError() after the response has been committed

    http://blog.csdn.net/chenghui0317/article/details/9531171 —————————————————————————————————————————— ...

  3. java.lang.IllegalStateException: Cannot call sendError() after the response has been committe

    1.问题描述 严重: Servlet.service() for servlet [default] in contextwith path [/OxygenCloud] threw exceptio ...

  4. Java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed

    在使用response重定向的时候,报以下错误:Java.lang.IllegalStateException: Cannot call sendRedirect() after the respon ...

  5. struts2异常记录--java.lang.IllegalStateException

    java.lang.IllegalStateException at org.apache.catalina.connector.ResponseFacade.sendError(ResponseFa ...

  6. java.lang.IllegalStateException at org.apache.catalina.connector.ResponseFacade

    2012-10-4 19:50:37 org.apache.catalina.core.StandardWrapperValve invoke 严重: Servlet.service() for se ...

  7. myeclipse 无法启动 java.lang.IllegalStateException: Unable to acquire application service. Ensure that the org.eclipse.core.runtime bundle is resolved and started (see config.ini).

    把myeclipse10 按照目录完整拷贝到了另外一台电脑, 另外的目录 原安装目录 D\:\soft\i\myeclipse10 新安装目录 E\:\soft\myeclipse10 双击启动失败, ...

  8. java.lang.IllegalStateException:Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.

    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.xxx...}: java.lang.IllegalSta ...

  9. java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead

    java.lang.IllegalStateException: Not allowed to create transaction on sharedEntityManager - use Spri ...

随机推荐

  1. vb6 的关机代码

    Public Const SE_PRIVILEGE_ENABLED As Integer = &H2Public Const TOKEN_QUERY As Integer = &H8P ...

  2. vc通过进程名返回进程id

    std::string WcharToChar(const wchar_t* wp, size_t m_encode = CP_ACP) { std::string str; , wp, wcslen ...

  3. JS在生成csv文件时,","逗号问题处理.

    在生成csv文件时,发现一个问题,因为csv文件本身是依靠逗号进行分列的,所以内容中有逗号时也被强制分列了,处理方法很简单,为内容加上双引号(英文格式)就可以了. 如: "11111,222 ...

  4. Redis搭建(七):Redis的Cluster集群动态增删节点

    一.引言 上一篇文章我们一步一步的教大家搭建了Redis的Cluster集群环境,形成了3个主节点和3个从节点的Cluster的环境.当然,大家可以使用 Cluster info 命令查看Cluste ...

  5. 【Python爬虫】听说你又闹书荒了?豆瓣读书9.0分书籍陪你过五一

    说明 五一将至,又到了学习的季节.目前流行的各大书单主打的都是豆瓣8.0评分书籍,却很少有人来聊聊这9.0评分的书籍长什么样子.刚好最近学了学python爬虫,那就拿豆瓣读书来练练手. 爬虫 本来思路 ...

  6. strip命令

    去掉文件里调试和符号信息,文件大小变小,一般在发布的时候使用. 主要作用于可执行文件,动态库,目标文件等. 可参考:http://blog.csdn.net/stpeace/article/detai ...

  7. WebLogic 12c CentOS7 静默安装

    JDK版本:1.8.0_161 Weblogic版本:12.2.1.3 一.前期准备 1.创建用户和组 # groupadd web # useradd -g web weblogic # passw ...

  8. hashlib 算法介绍

    Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等. 什么是摘要算法呢?摘要算法又称哈希算法.散列算法.它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制 ...

  9. CentOS 最新版的下载地址 + 版本选择详解

    CentOS 最新版的下载地址 + 版本选择详解 发现越来越多的机关单位.事业单位开始使用 Linux 作为主要服务器,毕竟,Linux的稳定性和高效性是众所周知的,所以我也打算把自己这一块技术加强一 ...

  10. tp5 根据经纬度计算门店距离 可排序

    $branchInfo=Db::name('Branch')->where('b_id','250')->find(); $map['p.cate_id']=array('eq',5); ...