Ajax sent directly PUT request, the backend can not receive data causes and solutions

I. Description of the problem:

    PUT request sent directly Ajax, but the object Spring MVC encapsulated, id fields other through the URI is successfully encapsulated with the data request body into an object is not enclosed.

    By testing, the request coming from the front end of the data; HttpServletRequest object by using request.getParameter () method but also not obtain data

image

Second, the solution:

    Add HttpPutFormContentFilter filter web.xml, looking down principle:

  1 <filter>
  2     <filter-name>httpPutFormContentFilter</filter-name>
  3     <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
  4 </filter>
  5 <filter-mapping>
  6     <filter-name>httpPutFormContentFilter</filter-name>
  7     <url-pattern>/*</url-pattern>
  8 </filter-mapping>

Third, the reasons for analysis:

Data will request body 1. Tomcat packaged as a Map, call request.getParameter () from this value will be the Map, Spring MVC POJO package when the object for each object attribute value is also called request.getParameter () method to acquire, and then assigned to the appropriate object properties, complete encapsulation properties.

Data 2. However, the PUT request, Tomcat package is not a request for the Map body, only the body of the POST request data request encapsulated into the Map; so, whether direct call request.getParameter () method, or Spring MVC package objects, certainly fail to get the value of the property.

Fourth, source code analysis:

1. Tomcat Request.java class source code org.apache.catalina.connector packet parseParameters () method is used to parse the request parameters, the method of the first series will be disposed and judgment, and then parse the request parameters. Wherein, the following code will request type is determined, if the conditions are met will directly return, i.e. is not determined parseBodyMethod request contains the current embodiment, if included, Tomcat server continues processing parameter resolution request body, the package to the Map; If not, return directly, rather than executing the following method of resolution parameters, then there is no Map in the corresponding parameters.

  1 if( !getConnector().isParseBodyMethod(getMethod()) ) {
  2     success = true;
  3     return;
  4 }

2. getConnector () method is used to obtain the currently connected, then call isParseBodyMethod () method of determining comprises parseBodyMethodSet set value is not passed in the method, this method is the current value of the request type.

  . 1  / **
   2   * Request.java class
   3   * retrieve the current embodiment
   . 4   * / 
  . 5  public String getMethod () {
   . 6      return coyoteRequest.method () toString ();.
   . 7 }
   . 8  
  . 9  / **
 10   * Connector .java class
 . 11   * / 
12 is  protected  Boolean isParseBodyMethod (String Method) {
 13 is       return parseBodyMethodsSet.contains (Method);
 14 }

3. parseBodyMethodSet are the default set of commonly used value, which is equivalent to the value assigned to the parseBodyMethods parseBodyMethodSet, and the default value is parseBodyMethods post.

  1  / **
   2    *调用setParseBodyMethods将getParseBodyMethods ()获取的parseBodyMethods的值赋值给
   3    * parseBodyMethods
   4    * / 
  5  protected  void initInternal () throws LifecycleException {
   6  
  7      // ... 
  8  
  9      // Make sure parseBodyMethodsSet has a default 
10      if ( null == parseBodyMethodsSet) {
 11          setParseBodyMethods (getParseBodyMethods ());
12      }
 13  
14      // ... 
15 }
 16  
17  / **
18   * value of the acquired parseBodyMethods
 . 19   * / 
20 is  protected String parseBodyMethods = " the POST ";
 21 is  
22 is  public String getParseBodyMethods () {
 23 is      return  the this .parseBodyMethods;
 24 }
 25  
26 is  / **
 27   * rules defined connector, if the connector allowing a non-member resolution request POST request, was introduced to the rule, the default is not
 28   * parseBodyMethodSet it uses the default value of
 29   * value is assigned to methods parseBodyMethods
 30   * methodSet value is assigned to parseBodyMethodsSet
 31 is   * / 
32  public  void setParseBodyMethods(String methods) {
 33 
 34     HashSet<String> methodSet = new HashSet<String>();
 35 
 36     if( null != methods ) {
 37         methodSet.addAll(Arrays.asList(methods.split("\\s*,\\s*")));
 38     }
 39 
 40     // ...
 41 
 42     this.parseBodyMethods = methods;
 43     this.parseBodyMethodsSet = methodSet;
 44 }

4. By a few steps in front of the analysis, parseBodyMethodSet only post default, only the current request when the only way is to post analytical parameters, therefore, whether directly through the Request object getParameter () or Spring MVC package POJO objects will not get the parameter value.

Five, HttpPutFormContentFilter filter principle

  1  / *
   2   * package data request body, repackaging Request object
   . 3   * / 
  . 4  protected  void doFilterInternal ( Final the HttpServletRequest Request, the HttpServletResponse Response, the FilterChain filterChain) throws ServletException, IOException {
   . 5      // put request, or when it is time to request patch 
  . 6      IF (( " the PUT " .equals (request.getMethod ()) || " the PATCH " .equals (request.getMethod ())) && the this .isFormContentType (Request)) {
   . 7          HttpInputMessage inputMessage = new new ServletServerHttpRequest (Request) {
   8             // Get the data stream in the request body, packaged into HttpInputMessage 
  . 9              public the InputStream the getBody () throws IOException {
 10                  return request.getInputStream ();
 . 11              }
 12 is          };
 13 is  
14          // The last step of the package into a package reading HttpInputMessage MultiValueMap object 
15          // this object inherits from the Map 
16          // data body encapsulates the request into the Map 
. 17          MultiValueMap <String, String> = formParameters the this .formConverter.read ((Class) null , inputMessage);
 18 is  
. 19          // use HttpPutFormContentRequestWrapper repackaging Request object 
20         = Warpper the HttpServletRequest new new HttpPutFormContentFilter.HttpPutFormContentRequestWrapper (Request, formParameters);
 21 is          the FilterChain.doFilter (warpper, Response);
 22 is      } the else {
 23 is          the FilterChain.doFilter (Request, Response);
 24      }
 25 }
 26 is  
27  / **
 28   * Packing Request concrete realization of the object
 29   * rewrite getParameter parent class () methods, first call the parent class of
 30   * If you can get is to get used to the parent class;
 31   * If you can not get, is to use the current class acquired.
32   * / 
33 is  Private  static  class HttpPutFormContentRequestWrapper extends 	HttpServletRequestWrapper {
 34       private MultiValueMap<String, String> formParameters;
 35 
 36       public String getParameter(String name) {
 37              String queryStringValue = super.getParameter(name);
 38              String formValue = (String)this.formParameters.getFirst(name);
 39              return queryStringValue != null ? queryStringValue : formValue;
 40       }
 41 
 42       // ...
 43 }

Guess you like

Origin www.cnblogs.com/lveyHang/p/11791412.html