为什么HttpServletRequest输入流为空?

Usm*_*ail 16 java servlets jetty guice

我有这个代码,我从请求输入流中读取输入并使用JacksonMapper转换为POJO.它在带有guice支撑的码头7容器中运行.

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    try {
        RequestType requestType = mapper.readValue(req.getInputStream(), RequestType.class);
    } Catch(Exception ex) {
        ....
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,有时在加载时会抛出以下异常.我检查了我的客户端,我确信它发送了一个有效的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(<generated>)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd$$FastClassByGuice$$c6f479ee.invoke(<generated>)
    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(<generated>)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.CGLIB$service$8(<generated>)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd$$FastClassByGuice$$c6f479ee.invoke(<generated>)
    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(<generated>)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.CGLIB$service$9(<generated>)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd$$FastClassByGuice$$c6f479ee.invoke(<generated>)
    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(<generated>)
    at com.google.inject.servlet.ServletDefinition.doService(ServletDefinition.java:263)
Run Code Online (Sandbox Code Playgroud)

djb*_*djb 15

我在运行Spring Boot应用程序时遇到了类似的问题.我的Spring Boot应用程序是一个简单的Dispatcherservlet,它读取请求主体并对其进行处理.

在我的例子中,curl如果curl命令行使用-d {some-data}并且没有设置特定的内容类型头,则client()设置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;
        }
Run Code Online (Sandbox Code Playgroud)

对于其他content-type值,Request返回此处,完成.

但是,如果内容类型匹配 application/x-www-form-urlencoded,则Request继续:

    try {
       if (readPostBody(formData, len) != len) {           
            parameters.setParseFailedReason(FailReason.REQUEST_BODY_INCOMPLETE);
            return;
        }
    } catch (....)
Run Code Online (Sandbox Code Playgroud)

这将消耗身体.所以在我的情况下,即使我的 servlet除了调用request.getInputStream()并尝试read()从它做什么之外什么也没做,它已经太晚了 - 运行时Request已经读取了输入并且没有缓冲或未读它.唯一的解决方法是设置不同的Content-Type.

罪魁祸首是 OrderedHiddenHttpMethodFilter(HiddenHttpMethodFilter).doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain)第70行

正在寻找"_method"查询参数.

我可以通过添加来禁用过滤器

@Bean
public FilterRegistrationBean registration(HiddenHttpMethodFilter filter) {
    FilterRegistrationBean registration = new FilterRegistrationBean(filter);
    registration.setEnabled(false);
    return registration;
}
Run Code Online (Sandbox Code Playgroud)

(用于解决另一个问题)


Bal*_*usC 13

如果它已经预先消耗,它将是空的.这将每当你叫隐式进行getParameter(),getParameterValues(),getParameterMap(),getReader(),等上HttpServletRequest.确保在调用之前不要调用任何需要从请求正文中收集信息的方法getInputStream().如果您的servlet没有这样做,那么开始检查映射在相同URL模式上的servlet过滤器.


更新:这似乎是GAE 1.5特定的.也可以看看

我担心在他们修复之前没有解决方案/解决方法.您可以尝试检查它是否在a中可用Filter,如果是,则将其复制并存储为请求属性.但这可能会影响某些GAE servlet的进一步处理.


Tob*_*ott 6

我遇到的问题是,我的请求InputStream在Jetty 6.1.15中始终为空,并且发现它是由缺少或错误的"Content-Type"标头引起的.

我使用HttpUrlConnection在另一个Java程序中生成请求.当我没有显式设置Content-Type标头时,接收程序中InputStream返回的by request.getInputStream()始终为空.当我将内容类型设置为"binary/octet-stream"时,InputStream请求包含正确的数据.

之前在请求对象上调用的唯一方法getInputStream()getContentLength().