这是最有趣的一行:
this.sc.send(msg, new HTTPServletResponseListener(response));
我怀疑这
sc是您正在呼叫的外部TCP服务器,并且您还会传递一个侦听器,以便在响应到达时得到通知。现在是一个重要的假设: TCP服务器异步发送响应
,在 另一个线程中 通知您的侦听器,对吗?
在这种情况下,它可以说明您的行为。在3.0之前的servlet中,您必须在中处理整个请求
doGet。一旦您的代码离开
doGet(),servlet容器就会假定整个请求已被处理并丢弃该请求。
您引入了一个 竞争条件
:
doGet()不向输出流写入任何内容而返回。容器需要几毫秒来处理响应并将其发送回。如果您的外部TCP服务器在短时间内返回数据并通知侦听器,则数据将通过。但是,如果服务器速度稍慢,则您正在发送对已处理的连接的响应。
可以这样考虑:浏览器进行呼叫,然后
doGet()又调用后端服务器。该
doGet()回报和servlet容器假定你做。它发回(空)响应,而忽略了该请求。毫秒甚至几秒后的响应从后端服务器返回。但是连接不见了,它已经被发送,套接字被关闭,浏览器呈现了响应。您没有在告诉您的容器:
嘿,等等,我还没有完成回复! 。
解决方案
从最坏到最好:
积极等待/轮询中的响应
doGet()
。阻止您的外部TCP服务器调用。更改TCP服务器外观,使其 返回
ResponseMessage
并将侦听器代码移至doGet()
。例:
ResponseMessage responseMsg = this.sc.send(msg); DataParser parser = new JSonParser(); String temp = parser.parseToString(responseMsg); httpResponse.setContentType("application/json"); httpResponse.addHeader("Hmm","yup"); PrintWriter out = httpResponse.getWriter(); out.println(temp);- 使用Servlet 3.0异步支持,这在您的用例中是一个更好的选择,更改范围将非常有限。
在
doGet():
final AsyncContext asyncContext = request.startAsync(request, response);
并在
HTTPServletResponseListener一旦你完成:
asyncContext.complete();
额外的调用
startAsync()告诉容器:
即使我从回来了
doGet(),我也没有完成此请求。请稍等。我前段时间写了一篇关于Servlet 3.0
的文章。



