为什么HttpServletRequest输入流为空?
我有这个代码,我从请求输入流中读取输入并使用JacksonMapper转换为POJO。 它在一个带有guice支撑的docker7容器中运行。
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { RequestType requestType = mapper.readValue(req.getInputStream(), RequestType.class); } Catch(Exception ex) { .... } }
但是,有时在加载时会抛出以下exception。 我检查了我的客户端,我确信它发送了一个有效的json字符串。 出了什么问题? Jetty 7在负载下的预期行为是什么?
java.io.EOFException: No content to map to Object due to end of input at org.codehaus.jackson.map.ObjectMapper._initForReading(ObjectMapper.java:2433) at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2385) at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1637) at com.ea.wsop.user.LoginServlet.processRequest(LoginServlet.java:69) at com.ea.wsop.user.LoginServlet.doPost(LoginServlet.java:63) at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.CGLIB$doPost$0() at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd$$FastClassByGuice$$c6f479ee.invoke() at com.google.inject.internal.cglib.proxy.$MethodProxy.invokeSuper(MethodProxy.java:228) at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:72) at com.ea.monitor.MethodExecutionTimer.invoke(MethodExecutionTimer.java:130) at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:72) at com.google.inject.internal.InterceptorStackCallback.intercept(InterceptorStackCallback.java:52) at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.doPost() at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.CGLIB$service$8() at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd$$FastClassByGuice$$c6f479ee.invoke() at com.google.inject.internal.cglib.proxy.$MethodProxy.invokeSuper(MethodProxy.java:228) at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:72) at com.ea.monitor.MethodExecutionTimer.invoke(MethodExecutionTimer.java:130) at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:72) at com.google.inject.internal.InterceptorStackCallback.intercept(InterceptorStackCallback.java:52) at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.service() at javax.servlet.http.HttpServlet.service(HttpServlet.java:820) at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.CGLIB$service$9() at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd$$FastClassByGuice$$c6f479ee.invoke() at com.google.inject.internal.cglib.proxy.$MethodProxy.invokeSuper(MethodProxy.java:228) at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:72) at com.ea.monitor.MethodExecutionTimer.invoke(MethodExecutionTimer.java:130) at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:72) at com.google.inject.internal.InterceptorStackCallback.intercept(InterceptorStackCallback.java:52) at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.service() at com.google.inject.servlet.ServletDefinition.doService(ServletDefinition.java:263)
如果它已经预先消耗,它将是空的。 只要在HttpServletRequest
上调用getParameter()
, getParameterValues()
, getParameterMap()
, getReader()
等,就会隐式执行此操作。 确保在调用getInputStream()
之前,不要调用任何需要从请求主体收集信息的方法。 如果您的servlet没有这样做,那么开始检查映射在相同URL模式上的servletfilter。
更新:这似乎是GAE 1.5特定的。 也可以看看
- http://code.google.com/p/googleappengine/issues/detail?id=5161
- http://code.google.com/p/googleappengine/issues/detail?id=5898
我担心在修复它之前没有解决方案/解决方法。 您可以尝试检查它是否在Filter
可用,如果是,则将其复制并存储为请求属性。 但这可能会影响某些GAE servlet的进一步处理。
我在运行Spring Boot应用程序时遇到了类似的问题。 我的Spring Boot应用程序是一个简单的Dispatcher
servlet,它读取请求主体并对其进行处理。
在我的例子中,如果curl命令行使用-d {some-data}
并且没有通过-Hcontent-type=some-other-media-type
设置特定的内容类型头,则客户端( curl
)设置application / x-www-form-urlencoded的内容类型头。 -Hcontent-type=some-other-media-type
。
在Spring Boot运行的Apache Catalina servlet引擎内部, Request
类在parseParameters()
进行以下测试
if (!("application/x-www-form-urlencoded".equals(contentType))) { success = true; return; }
对于其他content-type
值, Request
返回此处,完成。
但是,如果内容类型与 application/x-www-form-urlencoded
匹配 ,则Request
继续:
try { if (readPostBody(formData, len) != len) { parameters.setParseFailedReason(FailReason.REQUEST_BODY_INCOMPLETE); return; } } catch (....)
这将消耗身体 。 所以在我的情况下,即使我的 servlet除了调用request.getInputStream()
并尝试从它read()
之外什么都不做,它已经太晚了 – 运行时Request
已经读取了输入并且没有缓冲或未读取它。 唯一的解决方法是设置不同的Content-Type
。
罪魁祸首是OrderedHiddenHttpMethodFilter(HiddenHttpMethodFilter).doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain)
第70行
正在寻找"_method"
查询参数。
我可以通过添加禁用filter
@Bean public FilterRegistrationBean registration(HiddenHttpMethodFilter filter) { FilterRegistrationBean registration = new FilterRegistrationBean(filter); registration.setEnabled(false); return registration; }
(用于解决另一个问题 )
我遇到的问题是我的请求InputStream在Jetty 6.1.15中始终为空,并且发现它是由缺少或错误的“Content-Type”标头引起的。
我使用HttpUrlConnection在另一个Java程序中生成请求。 当我没有显式设置Content-Type标头时,接收程序中request.getInputStream()
返回的InputStream
始终为空。 当我将内容类型设置为“binary / octet-stream”时,请求的InputStream
包含正确的数据。
在getInputStream()
之前在请求对象上调用的唯一方法是getContentLength()
。
我正在使用mod_jk 1.2.39,它有一个导致此问题的错误。 更新到1.2.40后,它开始工作。
我有一个post有这个问题。 我通过FIRST读取输入流并将其放入缓存中来解决它,然后再读取参数。 这似乎可以解决问题
系统方法是:
- 获取容器的源代码,或者至少是Web部件(很难找到),在IDE中导入。
- 在调用
HttpServletRequest->getInputStream()
之前的代码中创建断点。 - 进入
HttpServletRequest->getInputStream()
方法,现在你在某些… Impl类。 - 在
getInputStream()
实现中设置一个新的断点,甚至在read()
方法中设置一个新的断点。 - 重复测试调用并查看消耗数据的内容。
- spark java:如何处理multipart / form-data输入?
- 同一个ip但不同端口上的两个服务器之间的JSESSIONID冲突
- 嵌入式Jetty和复杂日志记录
- UTF-8使用Tomcat编码servlet表单提交
- Jetty中的传输速度缓慢,在某些缓冲区大小时使用分块传输编码
- Jetty'{servlet} / {parameter}’url路由
- Jersey错误JAXBStringReaderProviders $ RootElementProvider
- 获取应用程序服务器下的真实(虚拟)主机名
- 如果从jar运行,带有嵌入式jetty的Spring应用程序找不到webdefault.xml