当我的用户使用Android设备连接JSON Rest服务时,我收到以下exception:
java.io.IOException: Socket read failed at org.apache.coyote.ajp.AjpProcessor.read(AjpProcessor.java:313) at org.apache.coyote.ajp.AjpProcessor.readMessage(AjpProcessor.java:364) at org.apache.coyote.ajp.AjpProcessor.receive(AjpProcessor.java:331) at org.apache.coyote.ajp.AbstractAjpProcessor.refillReadBuffer(AbstractAjpProcessor.java:614) at org.apache.coyote.ajp.AbstractAjpProcessor$SocketInputBuffer.doRead(AbstractAjpProcessor.java:1065) at org.apache.coyote.Request.doRead(Request.java:422) at org.apache.catalina.connector.InputBuffer.realReadBytes(InputBuffer.java:290) at org.apache.tomcat.util.buf.ByteChunk.substract(ByteChunk.java:431) at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:315) at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:200) at org.codehaus.jackson.impl.ByteSourceBootstrapper.ensureLoaded(ByteSourceBootstrapper.java:340) at org.codehaus.jackson.impl.ByteSourceBootstrapper.detectEncoding(ByteSourceBootstrapper.java:137) at org.codehaus.jackson.impl.ByteSourceBootstrapper.constructParser(ByteSourceBootstrapper.java:197) at org.codehaus.jackson.JsonFactory._createJsonParser(JsonFactory.java:542) at org.codehaus.jackson.JsonFactory.createJsonParser(JsonFactory.java:389) at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1454) at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.readInternal(MappingJacksonHttpMessageConverter.java:124) at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:153) at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.readWithMessageConverters(HandlerMethodInvoker.java:641) at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveRequestBody(HandlerMethodInvoker.java:605) at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:354) at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:171) at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:436) at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:424) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
我在跑步
这可能与超时有关吗? 就像客户端closures连接一样,服务器不能再从套接字读取? 或者更可能是服务器configuration的问题?
更新:
做一些Apache日志awk我发现以下Apache日志行对应于那些Tomcat日志exception:
192.186.30.116 - - [25/Jun/2012:10:47:14 +0200] "POST /myapp/methodX HTTP/1.1" 400 145 "-" "clientApp BlackBerry9360/7.0.0.530 VendorID/168" 10012655 192.186.30.120 - - [25/Jun/2012:10:53:13 +0200] "POST /myapp/methodY HTTP/1.1" 400 145 "-" "clientApp BlackBerry9800/6.0.0.668 VendorID/124" 10012164 192.186.30.116 - - [25/Jun/2012:10:53:36 +0200] "POST /myapp/methodZ HTTP/1.1" 400 145 "-" "clientApp BlackBerry9360/7.0.0.530 VendorID/168" 10012677 192.82.68.16 - - [25/Jun/2012:11:22:31 +0200] "POST /myapp/methodX HTTP/1.1" 400 145 "-" "clientApp BlackBerry9930/7.1.0.402 VendorID/104" 10012667 192.82.68.16 - - [25/Jun/2012:11:23:21 +0200] "POST /myapp/methodZ HTTP/1.1" 400 145 "-" "clientApp BlackBerry9930/7.1.0.402 VendorID/104" 10012562
您可以看到发送给客户端的这些请求的状态码400错误请求。
行末的大数字(例如10012562)显示请求在服务器上的处理时间(以微秒为单位): 10012562 =大约10秒
看起来连接10秒后终止了? 我看着AJPconfiguration,但没有超时定义 – 10秒将asynchronous请求,我不使用超时
我find了原因。 问题是由Apache模块mod_reqtimeout的默认configuration造成的:
<IfModule reqtimeout_module> # mod_reqtimeout limits the time waiting on the client to prevent an # attacker from causing a denial of service by opening many connections # but not sending requests. This file tries to give a sensible default # configuration, but it may be necessary to tune the timeout values to # the actual situation. Note that it is also possible to configure # mod_reqtimeout per virtual host. # Wait max 20 seconds for the first byte of the request line+headers # From then, require a minimum data rate of 500 bytes/s, but don't # wait longer than 40 seconds in total. # Note: Lower timeouts may make sense on non-ssl virtual hosts but can # cause problem with ssl enabled virtual hosts: This timeout includes # the time a browser may need to fetch the CRL for the certificate. If # the CRL server is not reachable, it may take more than 10 seconds # until the browser gives up. RequestReadTimeout header=20-40,minrate=500 # Wait max 10 seconds for the first byte of the request body (if any) # From then, require a minimum data rate of 500 bytes/s RequestReadTimeout body=10,minrate=500 </IfModule>
我猜BlackBerry客户端会更加难受,因为通过RIM BIS基础设施发送请求主体需要更长的时间。
将该值设置为100秒,并监视客户端是否仍然受到影响。
它看起来像是一个超时,但是你试过(或者有可能)通过Tomcat直接访问REST服务吗? (而不是通过apache / ajp)。 如果你尝试一下,并且看到你不再有这些exception,那么它可能是apache2 / mod_jk的东西。
在我以前的工作中,我发现mod_jk的某些版本在apache2下工作得更好(当然,我们并没有真的把这个做成严格的testing,我们只是使用了似乎在任何地方都能工作的版本,而没有改变它们,因为没有必要)