QueryString和FormData


HTTP请求中,如果是get请求,那么表单参数以name=value&name1=value1的形式附到url的后面,如果是post请求,那么表单参数是在请求体中,也是以name=value&name1=value1的形式在请求体中。我们先看一下我们的请求头
GET请求

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

Query String Parameters
name:mikan
address:street

可以看到我们的GET请求参数是被存放在QueryString 中的(可以通过request.getParameter() 获取请求参数)
POST请求

POST请求参数的存放位置是和我们的Content-Type 有关的

1.表单提交与Jquery异步请求

RequestURL:http://127.0.0.1:8080/test/test.do
Request Method:POST
Status Code:200 OK

Request Headers
Content-Type:application/x-www-form-urlencoded

Form Data
name:mikan
address:street

可以看到我们的POST请求参数是被存放在Form Data 中的(可以通过request.getParameter() 获取请求参数)

2.JS原生异步请求XMLHttpRequest

RequestURL:http://127.0.0.1:8080/test/test.do
Request Method:POST
Status Code:200 OK

Request Headers
Content-Type:text/plain;charset=UTF-8

Request Payload
name=mikan&address=street

注意同样是POST请求,默认的Content-Type:text/plain;charset=UTF-8 而且参数存放在了Request Payload (无法通过request.getParameter() 获取请求参数)

3.文件上传

Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryda3sd7BGGCFjy3P6

Request Payload
------WebKitFormBoundaryda3sd7BGGCFjy3P6
Content-Disposition: form-data; name="file"; filename="413.png"
Content-Type: image/png


------WebKitFormBoundaryda3sd7BGGCFjy3P6--

默认的Content-Type: multipart/form-data; 而且参数存放在了Request Payload

4.指定参数格式为Json的POST请求

Content-Type: application/json; charset=utf-8

Request Payload
{"option":"ZC","approveMsg":"参数","taskId":"8a948c4c5e363076015e36d0b4980004"}

默认的Content-Type: application/json; 而且参数存放在了Request Payload (无法通过request.getParameter() 获取请求参数)

基本的POST请求就上述的四种情况,我们最常用的就是表单的POST请求以及JQuery的POST异步请求,这种POST请求默认的Content-Type:application/x-www-form-urlencoded 也就是键值对的提交方式,而剩下的三种方式我们都无法通过
request.getParameter() 或者框架字段映射获取参数(这三种方式的Content-Type 都不为application/x-www-form-urlencoded), 那么原因何在呢?我们来看一下服务器接受请求的源码

protectedvoid parseParameters() {
//省略部分代码......
parameters.handleQueryParameters();// 这里是处理url中的参数
//省略部分代码......
if ("multipart/form-data".equals(contentType)) { // 这里是处理文件上传请求
    parseParts();
    success = true;
    return;
}

if(!("application/x-www-form-urlencoded".equals(contentType))) {// 这里如果是非POST请求直接返回,不再进行处理
    success = true;
    return;
}
//下面的代码才是处理POST请求参数
//省略部分代码......
try {
    if (readPostBody(formData, len)!= len) { // 读取请求体数据
        return;
    }
} catch (IOException e) {
    // Client disconnect
    if(context.getLogger().isDebugEnabled()) {
        context.getLogger().debug(
            sm.getString("coyoteRequest.parseParameters"),e);
    }
    return;
}
parameters.processParameters(formData, 0, len); // 处理POST请求参数,把它放到requestparameter map中(即request.getParameterMap获取到的Map,request.getParameter(name)也是从这个Map中获取的)
// 省略部分代码......
}
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;

}

我们可以看到只有在不是文件上传且ContentType是"application/x-www-form-urlencoded" 的时候 我们会将参数存放在Map中,而我们的request.getParameter 正是从此Map中取值,所以原因就很明了了

那我们如何接受上述的2,3,4方式的参数呢?

文件上传我们需要框架的支持,这里就不多说了
我们可以设置ContentType为"application/x-www-form-urlencoded" (通用)
ContentType为"application/json" 是以Json格式传输数据,我们后台可以使用@RequestBody 注解接受
ContentType为"text/plain" 的,我们可以使用流进行读取

private String getStringFromStream(HttpServletRequest req) {

    ServletInputStream is;
    try {
        is = req.getInputStream();
        int nRead = 1;
        int nTotalRead = 0;
        byte[] bytes = new byte[10240];
        while (nRead > 0) {
            nRead = is.read(bytes, nTotalRead, bytes.length - nTotalRead);
            if (nRead > 0)
                nTotalRead = nTotalRead + nRead;
        }
        String str = new String(bytes, 0, nTotalRead, "utf-8");
        return str;
    } catch (IOException e) {
        e.printStackTrace();
        return "";
    }
}
    String  rev = getStringFromStream(request);
    Object obj = JsonUtils.jsonToObj(rev,CompleteTaskVo.class);
    if(obj instanceof  CompleteTaskVo){
        params = (CompleteTaskVo)obj;
    }

总结
HTTP POST表单请求提交时:Content-Typeapplication/x-www-form-urlencoded,而使用原生AJAX的POST请求如果不指定请求头RequestHeader,默认使用的Content-Type是text/plain;charset=UTF-8。

表单提交数据是名值对的方式,而文件上传服务器需要特殊处理,普通的post请求数据格式不固定,不一定是名值对的方式,所以服务器无法知道具体的处理方式,所以只能通过获取原始数据流的方式来进行解析。jquery在执行post请求时,会设置Content-Type为application/x-www-form-urlencoded,所以服务器能够正确解析,而使用原生ajax请求时,如果不显示的设置Content-Type,那么默认是text/plain,这时不能用request.getParameter(name)的形式获取,所以才只能通过获取原始数据流的方式来进行解析请求数据。

声明:冰醋酸|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - QueryString和FormData


一切随缘