Servlet gets the method in which the parameters in the AJAX POST request are transmitted as form data and request payload

  • 2020-11-20 06:04:08
  • OfStack

This article illustrates how Servlet gets the parameters from AJAX POST requests in the form of form data and request payload. To share for your reference, the details are as follows:

In the HTTP request, if it is an get request, the form parameter is name=value & The form name1=value1 is appended to url. If it is an post request, the form parameter is in the body of the request, also as name=value & name1=value1 in the request body. From the chrome developer tools you can see the following (here is the readable form, not the request format of the real HTTP request protocol) :

get request:


RequestURL:http://127.0.0.1:8080/test/test.do?name=mikan&address=street
Request Method:GET
Status Code:200 OK
Request Headers
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip,deflate,sdch
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6
AlexaToolbar-ALX_NS_PH:AlexaToolbar/alxg-3.2
Connection:keep-alive
Cookie:JSESSIONID=74AC93F9F572980B6FC10474CD8EDD8D
Host:127.0.0.1:8080
Referer:http://127.0.0.1:8080/test/index.jsp
User-Agent:Mozilla/5.0 (Windows NT 6.1)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.149 Safari/537.36
Query String Parameters
name:mikan
address:street
Response Headers
Content-Length:2
Date:Sun, 11 May 2014 10:42:38 GMT
Server:Apache-Coyote/1.1

Post request:


RequestURL:http://127.0.0.1:8080/test/test.do
Request Method:POST
Status Code:200 OK
Request Headers
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip,deflate,sdch
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6
AlexaToolbar-ALX_NS_PH:AlexaToolbar/alxg-3.2
Cache-Control:max-age=0
Connection:keep-alive
Content-Length:25
Content-Type:application/x-www-form-urlencoded
Cookie:JSESSIONID=74AC93F9F572980B6FC10474CD8EDD8D
Host:127.0.0.1:8080
Origin:http://127.0.0.1:8080
Referer:http://127.0.0.1:8080/test/index.jsp
User-Agent:Mozilla/5.0 (Windows NT 6.1)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.149 Safari/537.36
Form Data
name:mikan
address:street
Response Headers
Content-Length:2
Date:Sun, 11 May 2014 11:05:33 GMT
Server:Apache-Coyote/1.1

Note here that the ES37en-ES38en for the post request is application/ ES40en-ES41en-ES42en-ES43en and the parameter is in the body of the request, Form Data in the request above.

In servlet, you can pass request.getParameter(name) To get the form parameters.

If using the native AJAX POST request:


function getXMLHttpRequest() {
     var xhr;
     if(window.ActiveXObject) {
          xhr= new ActiveXObject("Microsoft.XMLHTTP");
     }else if (window.XMLHttpRequest) {
          xhr= new XMLHttpRequest();
     }else {
          xhr= null;
     }
     return xhr;
}
function save() {
     var xhr = getXMLHttpRequest();
     xhr.open("post","http://127.0.0.1:8080/test/test.do");
     var data = "name=mikan&address=street...";
     xhr.send(data);
     xhr.onreadystatechange= function() {
          if(xhr.readyState == 4 && xhr.status == 200) {
              alert("returned:"+ xhr.responseText);
          }
     };
}

See the request header in chrome's developer tools as follows:


RequestURL:http://127.0.0.1:8080/test/test.do
Request Method:POST
Status Code:200 OK
Request Headers
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6
AlexaToolbar-ALX_NS_PH:AlexaToolbar/alxg-3.2
Connection:keep-alive
Content-Length:28
Content-Type:text/plain;charset=UTF-8
Cookie:JSESSIONID=C40C7823648E952E7C6F7D2E687A0A89
Host:127.0.0.1:8080
Origin:http://127.0.0.1:8080
Referer:http://127.0.0.1:8080/test/index.jsp
User-Agent:Mozilla/5.0 (Windows NT 6.1)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.149 Safari/537.36
Request Payload
name=mikan&address=street
Response Headers
Content-Length:2
Date:Sun, 11 May 2014 11:49:23 GMT
Server:Apache-Coyote/1.1

Note that the requested ES61en-ES62en is text/plain;charset=UTF-8 , while the request form parameters are in RequestPayload.

So in servlet request.getParameter(name) It is empty. Why is that? And how do you get such parameters?

In order to understand this problem, I looked up some information and also looked at the source code of Tomcat7.0.53 on request parameter processing. Finally, I figured out what happened.

Content-Type is used when the form request is submitted application/x-www-form-urlencoded For POST requests using the native AJAX, if the request header RequestHeader is not specified, the default is ES82en-ES83en text/plain;charset=UTF-8 .

Because Tomcat did "special handling" for ES88en-ES89en multipart/ form-ES92en (file upload) and application/ x-ES9en-ES96en-urlencoded (POST request). Let's take a look at the relevant processing code.

Tomcat HttpServletRequest implementation class for org. apache. catalina. connector. Request (is actually org. apache. coyote. Request), and for it to handle the request parameter method protected void parseParameters() , the processing code for ES113en-ES114en/ES116en-ES117en (file upload) and application/ ES119en-ES120en-ES121en-ES122en (POST request) in this method is as follows:


protectedvoid parseParameters() {
      // Omitted code ......
      parameters.handleQueryParameters();//  So here's processing url The parameters in the 
      // Omitted code ......
      if ("multipart/form-data".equals(contentType)) { //  This is for handling file upload requests 
        parseParts();
        success = true;
        return;
      }
      if(!("application/x-www-form-urlencoded".equals(contentType))) {//  If this is true or false POST The request is returned directly and is no longer processed 
        success = true;
        return;
      }
      // This is the code that handles it POST Request parameters 
      // Omitted code ......
      try {
        if (readPostBody(formData, len)!= len) { //  Read the request body data 
          return;
        }
      } catch (IOException e) {
        // Client disconnect
        if(context.getLogger().isDebugEnabled()) {
          context.getLogger().debug(
              sm.getString("coyoteRequest.parseParameters"),e);
        }
        return;
      }
      parameters.processParameters(formData, 0, len); //  To deal with POST Request parameter, put it in requestparameter map In the (i.e., request.getParameterMap To get to Map . request.getParameter(name) And also from this Map Obtained from) 
      //  Omitted code ......
}
protected int readPostBody(byte body[], int len)
    throws IOException {
    int offset = 0;
    do {
      int inputLen = getStream().read(body, offset, len - offset);
      if (inputLen <= 0) {
        return offset;
      }
      offset += inputLen;
    } while ((len - offset) > 0);
    return len;
}

As can be seen from the above code, Content-ES128en is not application/ ES130en-ES131en-ES132en-ES133en's POST request will not read the request body data and process the corresponding parameters, that is, it will not parse the form data to put into request parameter map. So through request.getParameter(name) You can't get it.

So how do we get the parameters that are committed like this?

The most primitive way, of course, is to read the input stream to get it, as follows:


privateString getRequestPayload(HttpServletRequest req) {
     StringBuildersb = new StringBuilder();
     try(BufferedReaderreader = req.getReader();) {
          char[]buff = new char[1024];
          intlen;
          while((len = reader.read(buff)) != -1) {
              sb.append(buff,0, len);
          }
     }catch (IOException e) {
          e.printStackTrace();
     }
     returnsb.toString();
}

Of course, the POST request with application/ ES147en-ES148en-ES149en-ES150en set can also be obtained this way.

Therefore, when using the native AJAX POST request, Request Header needs to be set explicitly, namely:


xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");

In addition, if I use jquery and I test with version 1.11.0, $.ajax post The request does not need to be explicitly set to the request header, and other versions have not been personally tested. It is believed that the version after 1.11.0 does not need to be set. But some of them were not fixed before. This has not been tested.

Postscript:

Only recently in my book did I really understand why the server does special processing for form submission and file upload, because the form submission data is the way of name-value pairs, and Content-ES168en is application/ ES170en-ES171en-ES172en-ES173en, while the file upload server needs special processing. Common post requests (Content-ES176en is not application/ ES178en-ES179en-ES179en-ES180en-ES181en) data format is not fixed, it is not the way of name-value pair, so the server cannot know the specific processing method, so it can only be parsed by getting the original data stream.

When jquery executes the post request, it will set ES186en-ES187en as application/ ES189en-ES190en-ES191en-ES192en, so the server can parse it correctly. However, when using the native ajax request, if Content-ES195en is not set, the default is text/plain. At this time, the server does not know how to parse the data, so it can only parse the request data by getting the original data stream.

For more information about java algorithm, please refer to Java Network programming Skills Summary, Java Data Structure and Algorithm Tutorial, Java Operation Of DOM Node Skills Summary, Java File and Directory Operation Skills Summary and Java Cache Operation Skills Summary.

I hope this article has been helpful in java programming.


Related articles: