[异常]java.lang.IllegalStateException: Cannot forward after response has been committed 的完美解决 for nutz

大部分的java.lang.IllegalStateException: Cannot forward after response has been committed

异常都是由于response对象在执行完一次向客户端的写操作后,

response.iscommt()==true

再执行一次写操作就会报这个异常.

 

我这次是在使用nutz时遇到的,

其实在其他环境遇到也一样能解决,

版本是1.b.37-rc.jar

 

-------------------------------异常栈

 
java.lang.IllegalStateException: Cannot forward after response has been committed
 at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:312)
 at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
 at org.nutz.mvc.view.ForwardView.render(ForwardView.java:64)
 at org.nutz.mvc.impl.processor.ViewProcessor.process(ViewProcessor.java:35)
 at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
 at org.nutz.mvc.impl.processor.MethodInvokeProcessor.process(MethodInvokeProcessor.java:23)
 at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
 at org.nutz.mvc.impl.processor.AdaptorProcessor.process(AdaptorProcessor.java:33)
 at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
 at org.nutz.mvc.impl.processor.ActionFiltersProcessor.process(ActionFiltersProcessor.java:42)
 at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
 at org.nutz.mvc.impl.processor.ModuleProcessor.process(ModuleProcessor.java:76)
 at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
 at org.nutz.mvc.impl.processor.EncodingProcessor.process(EncodingProcessor.java:27)
 at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
 at org.nutz.mvc.impl.processor.UpdateRequestAttributesProcessor.process(UpdateRequestAttributesProcessor.java:15)
 at org.nutz.mvc.impl.NutActionChain.doChain(NutActionChain.java:36)
 at org.nutz.mvc.impl.ActionInvoker.invoke(ActionInvoker.java:66)
 at org.nutz.mvc.ActionHandler.handle(ActionHandler.java:30)
 at org.nutz.mvc.NutFilter.doFilter(NutFilter.java:66)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
 at cn.com.fanna.managercontroller.web.filter.XFilter.doFilter(XFilter.java:26)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
 at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
 at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
 at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
 at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
 at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
 at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
 at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
 at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
 at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
 at java.lang.Thread.run(Unknown Source)
log4j: 2011-06-17 15:43:46,671 [http-8080-2] DEBUG org.nutz.mvc.impl.UrlMappingImpl - find mapping [null] for path [/img]

 

-----------------------------------------------------

关键是在调用org.nutz.mvc.impl.processor.*processor的doNext()方法时,

调用了iscommit()为true的response对象造成的,

我们只要在这以环节,

判断下iscommt(),

如==true,什么都不干返回,

否则,进行下个next.process()

 

org.nutz.mvc.impl.processo.

AbstractProcessor.java  

是关键,它是其他processors的超类,

所有就改它就可以了

代码:

关键代码:

 /**
  * 继续执行下一个Processor
  *

一般情形下都不应该覆盖这个方法
  * @param ac 执行方法的上下文
  * @throws Throwable
  */
 protected void doNext(ActionContext ac) throws Throwable {
  if(ac!=null&&ac.getResponse()!=null&&(!ac.getResponse().isCommitted())){  //就加这个判断就好了
   if (null != next)
    next.process(ac);
  }
  
 }

全部代码:

package org.nutz.mvc.impl.processor; import org.nutz.mvc.ActionContext; import org.nutz.mvc.ActionInfo; import org.nutz.mvc.NutConfig; import org.nutz.mvc.ObjectInfo; import org.nutz.mvc.Processor; import org.nutz.mvc.impl.Loadings; /** * 抽象的Processor实现. 任何Processor实现都应该继承这个类,以获取正确的执行逻辑. *

* @author zozoh([email protected]) * @author wendal([email protected]) * */ public abstract class AbstractProcessor implements Processor { private Processor next; /** * 建议覆盖这个方法,以便从NutConfig/ActionInfo获取需要的信息 */ public void init(NutConfig config, ActionInfo ai) throws Throwable { } /** * 设置下一个Processor *

一般情形下都不应该覆盖这个方法 * @param next 下一个Processor,一般不为null */ public void setNext(Processor next) { this.next = next; } /** * 继续执行下一个Processor *

一般情形下都不应该覆盖这个方法 * @param ac 执行方法的上下文 * @throws Throwable */ protected void doNext(ActionContext ac) throws Throwable { if(ac!=null&&ac.getResponse()!=null&&(!ac.getResponse().isCommitted())){ if (null != next) next.process(ac); } } protected static T evalObj(NutConfig config, ObjectInfo info) { return null == info ? null : Loadings.evalObj(config, info.getType(), info.getArgs()); } }

 

 

好了,将这个类单独编译出来,放到nutz的jar包中去,就可以了.

 

-------------------------------------------------------------------

Thinking:

之后问了nutz的作者兽哥,它说就不该让doNext有机会执行,

再次查看异常栈,

发现直接可以在

NutFilter.java做文章,

也就是nutz的启动类,

手段是一样的,

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain){}

方法中判断resp的isCommit()状态,做相应修改,应该是这个样子吧

 

 

 

  public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { if (!skipMode&&(!resp.isCommitted())) { RequestPath path = Mvcs.getRequestPathObject((HttpServletRequest) req); if (null == ignorePtn || !ignorePtn.matcher(path.getUrl()).find()) { if (handler.handle((HttpServletRequest) req, (HttpServletResponse) resp)) return; } } // 如果已经找到对应的action,而且正确处理,并且不是donext模式,那么不会走到这里 //更新 Request 必要的属性 Mvcs.updateRequestAttributes((HttpServletRequest) req); // 本过滤器没有找到入口函数,继续其他的过滤器 chain.doFilter(req, resp); }

 

 

ok ,这样一来,如果response被提交,直接让容器执行其它filter,

离开nutz的范围,与nutz无关了.

 

 

还是要感谢nutz的所有贡献者,让我学到了这个有趣的东西,

尤其是兽哥,每天在qq群里解答大家的各种疑问,

再次膜拜下你们.

你可能感兴趣的:(javaEE)