java Spring 的 @RequestBody 在 POST 上提供空字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5806724/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 12:52:14  来源:igfitidea点击:

Spring's @RequestBody providing empty string on POST

javaspringspring-mvc

提问by Johnco

I have an application with Spring 3.0.5.RELEASE trying to get the full content of a post using @RequestBody. The method is called, but the string passed is always empty. I have checked, by placing breakpoints, that the StringHttpMessageConverter is called, but the inner HttpInputMessage is empty.

我有一个带有 Spring 3.0.5.RELEASE 的应用程序,试图使用 @RequestBody 获取帖子的完整内容。方法被调用,但传递的字符串始终为空。我通过放置断点检查了 StringHttpMessageConverter 被调用,但内部 HttpInputMessage 是空的。

I've seen this issue with both Jetty and Tomcat, so I'm discarding it's a problem with the container.

我已经在 J​​etty 和 Tomcat 上看到了这个问题,所以我放弃了它是容器的问题。

Here is my sample controller:

这是我的示例控制器:

@Controller
@RequestMapping("/")
public class SubscriptionController {
    @RequestMapping(value = "/requestbody", method = RequestMethod.POST)
    public ModelAndView mycustomAction(@RequestBody String body) {

        // body is always empty
        Logger.getLogger(this.getClass()).debug("REQUEST BODY '" + body + "'");
        return new ModelAndView("empty");
    }
}

My application context is defined as follows:

我的应用程序上下文定义如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <!-- Enable auto detection of controllers -->
    <context:component-scan base-package="com.big.viajerotelcel.controller" />

    <!--
        use annotation driven mvc and one single validator with JSR-303
        standard
    -->
    <mvc:annotation-driven />

    <!--
        Message source for this context, loaded from localized "messages_xx"
        files
    -->

    <bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basenames" value="classpath:i18n/messages" />
        <property name="defaultEncoding" value="UTF-8" />
    </bean>

    <!-- Declare the Interceptor -->
    <mvc:interceptors>
        <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
            p:paramName="locale" />
    </mvc:interceptors>

    <!-- Declare the Resolver -->
    <bean id="localeResolver"
        class="org.springframework.web.servlet.i18n.SessionLocaleResolver" />

    <!-- will load Tiles definitions! -->
    <bean id="tilesConfigurer"
        class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
        <property name="definitions">
            <list>
                <value>/WEB-INF/general.xml</value>
            </list>
        </property>
    </bean>

    <!-- Tiles view resolver -->
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.tiles2.TilesView" />
    </bean>

    <!-- Configure the multipart resolver -->
    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--
            one of the properties available; the maximum file size in bytes (5MB)
        -->
        <property name="maxUploadSize" value="5120000" />
    </bean>

    <!-- Adding these lines has no effect, the StringHttpMessageConverter is called either way -->
<!--    <bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter"/>-->
<!--           -->
<!--    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">-->
<!--        <property name="messageConverters">-->
<!--          <list>-->
<!--            <ref bean="stringHttpMessageConverter"/>-->
<!--          </list>-->
<!--        </property>-->
<!--    </bean>-->
</beans>

I'm testing this using curl as follows:

我正在使用 curl 进行测试,如下所示:

curl -d asd=123 -d qwe=456 http://localhost:8080/requestbody

curl -d asd=123 -d qwe=456 http://localhost:8080/requestbody

Any ideas or help is more than welcomed!

任何想法或帮助都非常受欢迎!

采纳答案by Yoni

Here is a code snippet of ServletServerHttpRequest, which extends HttpInputMessage. I am pretty positive this is the implementation that you are using in your code:

这是 的代码片段ServletServerHttpRequest,它扩展了HttpInputMessage. 我很肯定这是您在代码中使用的实现:

public InputStream getBody() throws IOException {
    return this.servletRequest.getInputStream();
}

In other words, the request body is meant to be read as the input stream of the HttpServletRequestobject.

换句话说,请求正文旨在作为HttpServletRequest对象的输入流被读取。

The request's input stream is not valid in several situations, but I can't find the correct documentation for it at the moment. For example, if you call request.getParameter()on a post request, tomcat has to read the input stream in order to interpret the parameters, thus afterwards when you read the input stream, it is empty because it has reached the end already.

请求的输入流在多种情况下无效,但我目前找不到正确的文档。例如,如果您调用request.getParameter()post 请求,tomcat 必须读取输入流以解释参数,因此当您读取输入流时,它是空的,因为它已经到了结尾。

Perhaps you are invoking getParametersomewhere in an interceptor or perhaps a filter defined in web.xml. Another option is that Spring is doing that for you, for example, if your controller has some other method with complex @RequestMappings (such as reading param values, or header values).

也许您正在调用getParameter拦截器或 web.xml 中定义的过滤器中的某处。另一种选择是 Spring 正在为您执行此操作,例如,如果您的控制器有其他一些带有复杂@RequestMappings 的方法(例如读取参数值或标头值)。

I have two suggestions for you:

我有两个建议给你:

  1. Add a servlet filter (before spring gets a chance to act), and wrap the request with your own wrapper (just extend HttpServletRequestWrapper). This way you can put breakpoints or log messages at some methods of the request object and see who's calling them.

  2. Use a pojo object parameter, and setup the bindings. It seems like a much cleaner way to read post data.

  1. 添加一个 servlet 过滤器(在 spring 有机会采取行动之前),并用您自己的包装器包装请求(只需扩展HttpServletRequestWrapper)。通过这种方式,您可以在请求对象的某些方法上放置断点或记录消息,并查看谁在调用它们。

  2. 使用 pojo 对象参数,并设置绑定。这似乎是一种更简洁的方式来读取发布数据。

回答by Harshal Waghmare

Had a similar problem - the string received by spring controller was always empty. Tinkered with my spring config but with no result. Finally the problem was that the client was actually was not sending anything body!(due to some typo of mine)

有一个类似的问题 - 弹簧控制器收到的字符串总是空的。修改了我的弹簧配置,但没有结果。最后的问题是客户端实际上没有发送任何内容!(由于我的一些错字)

If found with a similar error, its worth checking once if the client's payload is actually non-empty.

如果发现有类似错误,则值得检查一次客户端的有效负载是否实际上是非空的。

回答by Joman68

Another reason that your XML may not be getting marshalled into your JAXB object is related to the namespaces in the XML.

您的 XML 可能没有被编组到您的 JAXB 对象中的另一个原因与 XML 中的名称空间有关。

Versions of java after 1.8.101 are more strict about parsing namespaced XML. See JAXB doesn't unmarshall after updating java from 1.8.0_77 to 1.8.0_121

1.8.101 之后的 java 版本对解析命名空间 XML 更加严格。请参阅将 java 从 1.8.0_77 更新到 1.8.0_121 后,JAXB 不会解组

In my case I was seeing a request body with all nulls and noexception being thrown to indicate that the XML parsing had failed.

在我的例子中,我看到一个请求体全部为空,并且没有抛出异常以表明 XML 解析失败。

回答by matt b

How are you POSTing messages to this URL? Are you positive that the HTTP request contains what you think it does? I suggest removing any web browsers from the picture and drop down to something low-level like curlwhich lets you send any type of HTTP message yourself.

您如何向此 URL 发布消息?您确定 HTTP 请求包含您认为的功能吗?我建议从图片中删除任何 Web 浏览器并下拉到低级别的内容,例如curl让您自己发送任何类型的 HTTP 消息。