Java 连接超时时的HttpServletResponse.flushBuffer()不会引发IOException
我面临着一个非常不寻常的情况。 我有两个Jboss(7.1)实例,它们通过HTTP进行通信。 实例A打开到实例B的HTTP连接,并发送一些要处理的数据。连接设置了超时,因此在N秒后,如果没有读取响应,则会抛出SocketTimeoutException。执行一些清理并关闭连接。 实例B有一个servlet,用于侦听此类http请求,并在收到请求时完成一些计算。之后,将填充响应并返回到客户端 问题是,如果计算花费太多时间,客户端(A)将由于超时而关闭连接,但服务器(B)将正常进行,并在一段时间后尝试发送响应。我希望能够检测到连接已关闭,并进行一些内部管理,但我似乎无法做到这一点 我已尝试调用HttpServletResponse.flushBuffer(),但未引发异常。我还显式地在http请求中设置了“Connection:close”以避免持久连接,但这没有效果。http servlet响应按正常方式进行处理,并毫无例外地消失在空白中。我不知道我做错了什么,我在这个网站上读到了其他问题,比如: 但它们在我的情况下不起作用 我认为JBossServlet容器可能有特定的东西,导致忽略或缓冲响应,或者http连接被重用,尽管我努力从客户端关闭它(A)。如果你能提供一些关于在哪里寻找问题的建议,我会很高兴的。我花了几天时间在这方面,没有取得任何相关进展,因此我需要紧急解决这一问题 以下是相关代码: 客户端代码(服务器A):Java 连接超时时的HttpServletResponse.flushBuffer()不会引发IOException,java,servlets,jboss,Java,Servlets,Jboss,我面临着一个非常不寻常的情况。 我有两个Jboss(7.1)实例,它们通过HTTP进行通信。 实例A打开到实例B的HTTP连接,并发送一些要处理的数据。连接设置了超时,因此在N秒后,如果没有读取响应,则会抛出SocketTimeoutException。执行一些清理并关闭连接。 实例B有一个servlet,用于侦听此类http请求,并在收到请求时完成一些计算。之后,将填充响应并返回到客户端 问题是,如果计算花费太多时间,客户端(A)将由于超时而关闭连接,但服务器(B)将正常进行,并在一段时间后尝
private static int postContent(URL destination, String fileName, InputStream content)
throws IOException, CRPostException
{
HttpURLConnection connection = null;
//Create the connection object
connection = (HttpURLConnection)destination.openConnection();
// Prepare the HTTP headers
connection.setDoOutput(true);
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("content-type", "text/xml; charset=UTF-8");
connection.setRequestProperty("Content-Encoding", "zip");
connection.setRequestProperty("Connection", "close");//Try to make it non-persistent
//Timouts
connection.setConnectTimeout(20000);//20 sec timout
connection.setReadTimeout(20000);//20 sec read timeout
// Connect to the remote system
connection.connect();
try
{
//Write something to the output stream
writeContent(connection, fileName, content);
//Handle response from server
return handleResponse(connection);
}
finally
{
try
{
try
{
connection.getInputStream().close();//Try to explicitly close the connection
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
connection.disconnect();//Close the connection??
}
catch (Exception e)
{
logger.warning("Failed to disconnect the HTTP connection");
}
}
}
private static int handleResponse(HttpURLConnection connection)
throws IOException, CRPostException
{
String responseMessage = connection.getResponseMessage();//Where it blocks until server returns the response
int statusCode = connection.getResponseCode();
if (statusCode == HttpURLConnection.HTTP_OK)
{
logger.debug("HTTP status code OK");
InputStream in = connection.getInputStream();
try
{
if (in != null)
{
//Read the result, parse it and return it
....
}
}
catch (JAXBException e)
{
}
}// if
//return error state
return STATE_REJECTED;
}//handleResponse()
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String crXML = null;
MediaType mediaType = null;
Object result;
// Get the media type of the received CR XML
try
{
mediaType = getMediaType(request);
crXML = loadDatatoString(mediaType, request);
result = apply(crXML);
}
catch (Exception e)
{
logger.error("Application of uploaded data has failed");
//Return response that error has occured
....
return;
}
// Finally prepare the OK response
buildStatusResponse(response, result);
// Try to detect that the connection is broken
// and the resonse never got to the client
// and do some housekeeping if so
try
{
response.getOutputStream().flush();
response.flushBuffer();
}
catch (Throwable thr)
{
// Exception is never thrown !!!
// I expect to get an IO exception if the connection has timed out on the client
// but this never happens
thr.printStackTrace();
}
}// doPost(..)
public static void buildStatusResponse(HttpServletResponse responseArg, Object result)
{
responseArg.setHeader("Connection", "close");//Try to set non persistent connection on the response too - no effect
responseArg.setStatus(HttpServletResponse.SC_OK);
// write response object
ByteArrayOutputStream respBinaryOut = null;
try
{
respBinaryOut = new ByteArrayOutputStream();
OutputStreamWriter respWriter = new OutputStreamWriter(respBinaryOut, "UTF-8");
JAXBTools.marshalStatusResponse(result, respWriter);
}
catch (Exception e)
{
logger.error("Failed to write the response object", e);
return;
}
try
{
responseArg.setContentType(ICRConstants.HTTP_CONTENTTYPE_XML_UTF8);
responseArg.getOutputStream().write(respBinaryOut.toByteArray());
}
catch (IOException e)
{
logger.error("Failed to write response object in the HTTP response body!", e);
}
}//buildStatusResponse()
服务器代码(服务器B):
private static int postContent(URL destination, String fileName, InputStream content)
throws IOException, CRPostException
{
HttpURLConnection connection = null;
//Create the connection object
connection = (HttpURLConnection)destination.openConnection();
// Prepare the HTTP headers
connection.setDoOutput(true);
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("content-type", "text/xml; charset=UTF-8");
connection.setRequestProperty("Content-Encoding", "zip");
connection.setRequestProperty("Connection", "close");//Try to make it non-persistent
//Timouts
connection.setConnectTimeout(20000);//20 sec timout
connection.setReadTimeout(20000);//20 sec read timeout
// Connect to the remote system
connection.connect();
try
{
//Write something to the output stream
writeContent(connection, fileName, content);
//Handle response from server
return handleResponse(connection);
}
finally
{
try
{
try
{
connection.getInputStream().close();//Try to explicitly close the connection
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
connection.disconnect();//Close the connection??
}
catch (Exception e)
{
logger.warning("Failed to disconnect the HTTP connection");
}
}
}
private static int handleResponse(HttpURLConnection connection)
throws IOException, CRPostException
{
String responseMessage = connection.getResponseMessage();//Where it blocks until server returns the response
int statusCode = connection.getResponseCode();
if (statusCode == HttpURLConnection.HTTP_OK)
{
logger.debug("HTTP status code OK");
InputStream in = connection.getInputStream();
try
{
if (in != null)
{
//Read the result, parse it and return it
....
}
}
catch (JAXBException e)
{
}
}// if
//return error state
return STATE_REJECTED;
}//handleResponse()
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String crXML = null;
MediaType mediaType = null;
Object result;
// Get the media type of the received CR XML
try
{
mediaType = getMediaType(request);
crXML = loadDatatoString(mediaType, request);
result = apply(crXML);
}
catch (Exception e)
{
logger.error("Application of uploaded data has failed");
//Return response that error has occured
....
return;
}
// Finally prepare the OK response
buildStatusResponse(response, result);
// Try to detect that the connection is broken
// and the resonse never got to the client
// and do some housekeeping if so
try
{
response.getOutputStream().flush();
response.flushBuffer();
}
catch (Throwable thr)
{
// Exception is never thrown !!!
// I expect to get an IO exception if the connection has timed out on the client
// but this never happens
thr.printStackTrace();
}
}// doPost(..)
public static void buildStatusResponse(HttpServletResponse responseArg, Object result)
{
responseArg.setHeader("Connection", "close");//Try to set non persistent connection on the response too - no effect
responseArg.setStatus(HttpServletResponse.SC_OK);
// write response object
ByteArrayOutputStream respBinaryOut = null;
try
{
respBinaryOut = new ByteArrayOutputStream();
OutputStreamWriter respWriter = new OutputStreamWriter(respBinaryOut, "UTF-8");
JAXBTools.marshalStatusResponse(result, respWriter);
}
catch (Exception e)
{
logger.error("Failed to write the response object", e);
return;
}
try
{
responseArg.setContentType(ICRConstants.HTTP_CONTENTTYPE_XML_UTF8);
responseArg.getOutputStream().write(respBinaryOut.toByteArray());
}
catch (IOException e)
{
logger.error("Failed to write response object in the HTTP response body!", e);
}
}//buildStatusResponse()
您正在客户端运行HTTP连接池。物理连接并没有真正关闭,它会返回到池中,以备将来重用。如果它空闲一段时间,它将关闭并从池中删除。因此,在服务器flushBuffer()发生时,连接仍然处于活动状态 或
正在刷新的数据足够小,可以放入发送方的套接字发送缓冲区,因此底层写操作立即成功返回,而断开连接只是在稍后通过TCP异步发现的。服务器端似乎确实存在一些缓冲。HttpServletResponse缓冲区大小报告为8192字节。我的响应很小—大约300字节,因此我创建了一个大字节数组—18000字节,并尝试刷新它。现在我得到了:ClientAbortException:java.net.SocketException:Software-caused-connection-abort:socket-write-error。看来你的第二个建议是正确的。不知我是否可以为servlet响应配置缓冲区大小?