我在本地开发服务器上测试了以下一段代码,其输入网址响应缓慢。
final HttpGet getMethod = getHttpGet(apiUrl);
RequestConfig config = RequestConfig.custom()
.setSocketTimeout(60 * 1000)
.setConnectTimeout(60 * 1000)
.setConnectionRequestTimeout(60 * 1000)
.build();
getMethod.setConfig(config);
httpClient = HttpClients.createDefault();
proxyResponse = httpClient.execute(getMethod);
if (proxyResponse.getStatusLine().getStatusCode() == HTTP_OK) {
/* ... */
}
虽然套接字超时设置为60秒,但在6秒后我们看到org.apache.http.impl.execchain.RetryExec正在重试。在4次重试之后,请求失败并出现异常。看起来超时信息被忽略了。
INFO: Pre-render service making request:
Apr 15, 2014 4:49:01 PM com.github.greengerong.PreRenderSEOFilter dump
INFO: GET http://api.ajaxsnapshots.com/makeSnapshot?url=http%3A%2F%2Fkarmademo.dyndns.dk%3A8080%2F HTTP/1.1
...
Apr 15, 2014 4:49:07 PM org.apache.http.impl.execchain.RetryExec execute
INFO: I/O exception (java.net.SocketException) caught when processing request: Socket operation timed out: The API call remote_socket.Receive() took too long to respond and was cancelled.
Apr 15, 2014 4:49:07 PM org.apache.http.impl.execchain.RetryExec execute
INFO: Retrying request
...
Apr 15, 2014 4:49:12 PM org.apache.http.impl.execchain.RetryExec execute
INFO: I/O exception (java.net.SocketException) caught when processing request: Socket operation timed out: The API call remote_socket.Receive() took too long to respond and was cancelled.
Apr 15, 2014 4:49:12 PM org.apache.http.impl.execchain.RetryExec execute
INFO: Retrying request
...
Apr 15, 2014 4:49:17 PM org.apache.http.impl.execchain.RetryExec execute
INFO: I/O exception (java.net.SocketException) caught when processing request: Socket operation timed out: The API call remote_socket.Receive() took too long to respond and was cancelled.
Apr 15, 2014 4:49:17 PM org.apache.http.impl.execchain.RetryExec execute
INFO: Retrying request
...
Apr 15, 2014 4:49:22 PM com.github.greengerong.PreRenderSEOFilter doFilter
WARNING: Prerender service error
java.net.SocketException: Socket operation timed out: The API call remote_socket.Receive() took too long to respond and was cancelled.
at com.google.appengine.api.socket.SocketApiHelper.makeSyncCall(SocketApiHelper.java:73)
at com.google.appengine.api.socket.AppEngineSocketImpl.receive(AppEngineSocketImpl.java:710)
at com.google.appengine.api.socket.AppEngineSocketInputStream.read(AppEngineSocketInputStream.java:35)
at org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:136)
at org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:152)
at org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:270)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:140)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:57)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:260)
at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:161)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.google.appengine.tools.development.agent.runtime.Runtime.invoke(Runtime.java:115)
at org.apache.http.impl.conn.CPoolProxy.invoke(CPoolProxy.java:138)
at com.sun.proxy.$Proxy49.receiveResponseHeader(Unknown Source)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:271)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:123)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:253)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:194)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:85)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)
at com.github.greengerong.PreRenderSEOFilter.proxyPrerenderedPageResponse(PreRenderSEOFilter.java:132)
at com.github.greengerong.PreRenderSEOFilter.doFilter(PreRenderSEOFilter.java:84)
我切换到使用HttpURLConnection,我能够成功控制读取超时。
URL url = new URL(apiUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setReadTimeout(60 * 1000);
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
/* ... */
}
不确定为什么使用org.apache api我无法调整超时。只是想我发布以防万一有人知道,更重要的是,确保人们了解解决方法。
版本信息: