DANTE

WebSphere上遇到的两个问题

第一个问题

在部署到WebSphere的Web应用程序中有如下代码,遍历所有的Servlet注册信息,将它们的映射全部添加到一个Set里:

for (ServletRegistration servletRegistration : servletContext.getServletRegistrations().values()) {
  mappingsSet.addAll(servletRegistration.getMappings());
}

这段代码执行时,在Set.addAll()方法中抛了NullPointerException。显然,某次getMappings()方法调用返回了null值。

但是根据ServletRegistration的JavaDoc,getMappings()方法永远不应该返回null

Returns:
a (possibly empty) Collection of the currently available mappings of the Servlet represented by this ServletRegistration

如果一个Servlet并没有与之相关的任何路径映射,那么对应的getMappings()应该返回一个空的Collection。显然,WebSphere并没有遵守这一要求,这应该是个Bug。

简单搜索一下就能找到一篇IBM知识库文章,里面介绍了对这个Bug的解决方法:在WebSphere应用服务器的Web Container(Web容器)设置中,添加一个自定义属性,来启用满足Servlet 3.0标准的行为。当然,也可以简单地在自己的程序里加一个null check。

说真的,程序有Bug不奇怪,但是对这种明显不符合标准要求的Bug,还需要用户设置一个属性才能真的真的修复,实在是理解不了。

第二个问题

第二个问题要复杂很多,因为完全没有任何的错误信息。

事情是这样的。

部署在WebSphere上的Web应用程序,在web.xml里为所有的Servlet和Filter设置了<async-supported>true</async-supported>。这样一来,请求处理链上最末端的Servlet就可以调用ServletRequest.startAsync()来使用Servlet标准提供的Async功能。

然而在浏览器中访问的时候,页面直接白屏。用浏览器的调试工具查看,发现服务器返回的HTTP响应中只有头(Header),没有内容(Body)。而只要将处理链上随便某一个Servlet或者Filter上的async-supported声明去掉,页面就可以正常显示了。

由于没有报错输出,用Google搜索也没发现有价值的信息,一开始就陷入了僵局,只能通过调试代码来定位问题了。

经过调试发现,由于HttpServletResponse被提前commit了,Web应用跳过了一部分页面的渲染,也没有将已经渲染了的部分写出去。那么为什么async-supported会导致这样的情况发生呢?

实际上,对于Async功能,Servlet标准中有如下要求:

Async support will be disabled as soon as the request has passed a filter or servlet that does not support async processing (either via the designated annotation or declaratively).
The response will be committed when the service method of the servlet that does not support async is exited.

就是说,如果Request经过了一个“不支持Async”的Servlet或者Filter,在这之后该请求将被标记为不支持Async;在从这个“不支持Async”的Servlet返回之后,对应的Response要被commit。

而问题正出在这里。Web应用的请求处理链上有一个JSP,也就是说,Request在处理过程中会被Dispatch到一个JSP上,再由这个JSP继续Dispatch到别的Servlet。在WebSphere中,一个请求只要经过了JSP编译出的Servlet,就会被标记为“不支持Async”,同时,在从这个JSP Servlet返回的时候,对应的Response就被commit了。

同一个Web应用在Tomcat上可以正常工作,显然Tomcat并没有将JSP Servlet标记为“不支持Async”。虽说对于这方面,Servlet标准可能没有明确的规定,但是还是对WebSphere好不爽啊……

评论