我们发送一个请求时,服务端的javax.servlet.http.HttpServletRequest帮我们做了什么?

本文探讨了在web应用程序中,如何使用javax.servlet.http.HttpServletRequest来获取和解析请求数据。通过一系列示例,展示了HttpServletRequest如何处理GET和POST请求,包括不同类型的queryParams和bodyParams,以及它们在请求对象中的存储方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在web应用程序中,后台仅仅获取请求参数是远远不够的。比如,spring的controller层,我们可以通过@RequestMapping注解一个方法使其成为web借口,我们可以通过方法参数来获取匹配获取请求的参数。 但是,如果我们想要获取更多的信息怎么办呢?
没错,用javax.servlet.http.HttpServletRequest,HttpServletRequest帮我们将请求解析封装好了已经,我们只需要拿来直接用即可。

举个例子

(HttpServletRequest在springMVC/springBoot Controller层的应用)

 @RequestMapping(value = "/**")
public ResponseEntity<Object> mockEntry(HttpServletRequest httpServletRequest) {
    return new ResponseEntity<Object>("mock match!", HttpStatus.OK);
}

在方法mockEntry中,可以通过httpServletRequest实例提供的方法获取到各种请求数据。


我们来看不同请求下,HttpServletRequest将请求封装成什么样子了。 我们将验证一下请求:

1、 GET方法,不带queryParams;

curl 'http://localhost:8089/my/url'

2、GET方法,带queryParams;

curl 'http://localhost:8089/my/url?key1=value1&key2=vlaue2'

3、POST方法,bodyType为application/x-www-form-urlencoded,不带queryParams,不带bodyParams;

curl -H 'Content-Type:application/x-www-form-urlencoded' -d '' 'http://localhost:8089/my/url'

4、POST方法,bodyType为application/x-www-form-urlencoded,不带queryParams,带bodyParams;

curl -H 'Content-Type:application/x-www-form-urlencoded' -d 'key=value' 'http://localhost:8089/my/url'

5、POST方法,bodyType为application/x-www-form-urlencoded,带queryParams,不带bodyParams;

curl -H 'Content-Type:application/x-www-form-urlencoded' -d '' 'http://localhost:8089/my/url?key=value'

6、POST方法,bodyType为application/x-www-form-urlencoded,带queryParams,带bodyParams;

curl -H 'Content-Type:application/x-www-form-urlencoded' -d 'key1=value1' 'http://localhost:8089/my/url?key2=value2'

7、POST方法,bodyType为application/json,不带queryParams,不带bodyParams;

curl -H 'Content-Type:application/json' -d '' 'http://localhost:8089/my/url'

8、POST方法,bodyType为application/json,不带queryParams,带bodyParams;

curl -H 'Content-Type:application/json' -d '{"key": "value"}' 'http://localhost:8089/my/url'

9、POST方法,bodyType为application/json,带queryParams,不带bodyParams;

curl -H 'Content-Type:application/json' -d '' 'http://localhost:8089/my/url?key=value'

10、POST方法,bodyType为application/json,带queryParams,带bodyParams;

curl -H 'Content-Type:application/json' -d '{"key": "value"}' 'http://localhost:8089/my/url?key2=value2'


准备工作

我们写一个Filter,并且写一个RequestMetadata作为数据承载类,为我们直观的输出HttpServletRequest封装了什么。

import java.io.Serializable;
import java.util.Map;

public class RequestMetadata implements Serializable {

    private static final long serialVersionUID = 4756023942925621584L;
    private String protocol;
    private String scheme;
    private String serverName;
    private String serverPort;
    private String servletPath;
    private String method;
    private String uri;
    private String url;
    private String contentType;
    private int contentLength;
    private Map<String, String> headerNames;
    private String queryString;
    private Map<String, String> parameterMap;
    private String body;

    public RequestMetadata() {
    }

    public String getProtocol() {
        return protocol;
    }

    public void setProtocol(String protocol) {
        this.protocol = protocol;
    }

    public String getScheme() {
        return scheme;
    }

    public void setScheme(String scheme) {
        this.scheme = scheme;
    }

    public String getServerName() {
        return serverName;
    }

    public void setServerName(String serverName) {
        this.serverName = serverName;
    }

    public String getServerPort() {
        return serverPort;
    }

    public void setServerPort(String serverPort) {
        this.serverPort = serverPort;
    }

    public String getServletPath() {
        return servletPath;
    }

    public void setServletPath(String servletPath) {
        this.servletPath = servletPath;
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    public String getUri() {
        return uri;
    }

    public void setUri(String uri) {
        this.uri = uri;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getContentType() {
        return contentType;
    }

    public void setContentType(String contentType) {
        this.contentType = contentType;
    }

    public int getContentLength() {
        return contentLength;
    }

    public void setContentLength(int contentLength) {
        this.contentLength = contentLength;
    }

    public Map<String, String> getHeaderNames() {
        return headerNames;
    }

    public void setHeaderNames(Map<String, String> headerNames) {
        this.headerNames = headerNames;
    }

    public String getQueryString() {
        return queryString;
    }

    public void setQueryString(String queryString) {
        this.queryString = queryString;
    }

    public Map<String, String> getParameterMap() {
        return parameterMap;
    }

    public void setParameterMap(Map<String, String> parameterMap) {
        this.parameterMap = parameterMap;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

    @Override
    public String toString() {
        return "RequestMetadata{" +
                "protocol='" + protocol + '\'' +
                ", scheme='" + scheme + '\'' +
                ", serverName='" + serverName + '\'' +
                ", serverPort='" + serverPort + '\'' +
                ", servletPath='" + servletPath + '\'' +
                ", method='" + method + '\'' +
                ", uri='" + uri + '\'' +
                ", url='" + url + '\'' +
                ", contentType='" + contentType + '\'' +
                ", contentLength=" + contentLength +
                ", headerNames=" + headerNames +
                ", queryString='" + queryString + '\'' +
                ", parameterMap=" + parameterMap +
                ", body='" + body + '\'' +
                '}';
    }
}
import java.io.IOException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.filter.OncePerRequestFilter;

import wiremock.com.google.common.collect.Maps;

/**
 * Filter all requests. Extract useful information from the request (for example: method, parameter, uri, etc.) and
 * store it in a map. An http request will first go to this Filter, and then go to the Controller class, so this map is
 * stored in the ThreadLocal in order to obtain the details of the request at the Controller level.
 */
@WebFilter(filterName = "requestFilter", urlPatterns = "/*")
public class RequestFilter extends OncePerRequestFilter {

    private static final Logger logger      = LoggerFactory.getLogger(RequestFilter.class);

    public static ThreadLocal   threadLocal = new ThreadLocal();

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                                    FilterChain filterChain) throws ServletException, IOException {

        RequestMetadata requestMetadata = new RequestMetadata();
        ServletRequest requestWrapper = null;

        requestMetadata.setProtocol(httpServletRequest.getProtocol());
        requestMetadata.setScheme(httpServletRequest.getScheme());
        requestMetadata.setServerName(httpServletRequest.getServerName());
        requestMetadata.setServerPort(String.valueOf(httpServletRequest.getServerPort()));
        requestMetadata.setServletPath(httpServletRequest.getServletPath());
        requestMetadata.setMethod(httpServletRequest.getMethod());
        requestMetadata.setUri(httpServletRequest.getRequestURI());
        requestMetadata.setUrl(httpServletRequest.getRequestURL().toString());
        requestMetadata.setContentType(httpServletRequest.getContentType());
        requestMetadata.setContentLength(httpServletRequest.getContentLength());
        requestMetadata.setQueryString(httpServletRequest.getQueryString());

        // headerNames
        Map<String, String> headersMap = Maps.newHashMap();
        Enumeration<String> headerNamesEnumeration = httpServletRequest.getHeaderNames();
        while (headerNamesEnumeration.hasMoreElements()) {
            String key = headerNamesEnumeration.nextElement();
            headersMap.put(key, httpServletRequest.getHeader(key));
        }
        requestMetadata.setHeaderNames(headersMap);

        // parameterMap
        Map<String, String> parameterMap = Maps.newHashMap();
        Iterator iterator = httpServletRequest.getParameterMap().entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, String[]> entry = (Map.Entry<String, String[]>) iterator.next();
            parameterMap.put(entry.getKey(), entry.getValue()[0]);
        }
        requestMetadata.setParameterMap(parameterMap);

        requestWrapper = new BodyReaderHttpServletRequestWrapper(httpServletRequest);
        byte[] body = ((BodyReaderHttpServletRequestWrapper) requestWrapper).getBody();
        requestMetadata.setBody(new String(body));

        // Save the requestMetadata containing the request details in threadLocal
        threadLocal.set(requestMetadata);

        if (null == requestWrapper) {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
        } else {
            filterChain.doFilter(requestWrapper, httpServletResponse);
        }
    }
}

验证

1、 GET方法,不带queryParams;
请求
curl 'http://localhost:8089/my/url'

打印JSON.toJSONString(requestMetadata)

{
    "body": "",
    "contentLength": -1,
    "headerNames": {
        "host": "localhost:8089",
        "user-agent": "curl/7.54.0",
        "accept": "*/*"
    },
    "method": "GET",
    "parameterMap": {
    },
    "protocol": "HTTP/1.1",
    "scheme": "http",
    "serverName": "localhost",
    "serverPort": "8089",
    "servletPath": "/my/url",
    "uri": "/my/url",
    "url": "http://localhost:8089/my/url"
}

2、GET方法,带queryParams;
请求
curl 'http://localhost:8089/my/url?key1=value1&key2=vlaue2'

打印JSON.toJSONString(requestMetadata)

{
    "body": "",
    "contentLength": -1,
    "headerNames": {
        "host": "localhost:8089",
        "user-agent": "curl/7.54.0",
        "accept": "*/*"
    },
    "method": "GET",
    "parameterMap": {
        "key1": "value1",
        "key2": "vlaue2"
    },
    "protocol": "HTTP/1.1",
    "queryString": "key1=value1&key2=vlaue2",
    "scheme": "http",
    "serverName": "localhost",
    "serverPort": "8089",
    "servletPath": "/my/url",
    "uri": "/my/url",
    "url": "http://localhost:8089/my/url"
}

注:GET方法的queryParams,存储到了以parameterMap为key的JSONObject中。

3、POST方法,bodyType为application/x-www-form-urlencoded,不带queryParams,不带bodyParams;
请求
curl -H 'Content-Type:application/x-www-form-urlencoded' -d '' 'http://localhost:8089/my/url'

打印JSON.toJSONString(requestMetadata)

{
    "body": "",
    "contentLength": 0,
    "contentType": "application/x-www-form-urlencoded",
    "headerNames": {
        "content-length": "0",
        "host": "localhost:8089",
        "content-type": "application/x-www-form-urlencoded",
        "user-agent": "curl/7.54.0",
        "accept": "*/*"
    },
    "method": "POST",
    "parameterMap": {
    },
    "protocol": "HTTP/1.1",
    "scheme": "http",
    "serverName": "localhost",
    "serverPort": "8089",
    "servletPath": "/my/url",
    "uri": "/my/url",
    "url": "http://localhost:8089/my/url"
}

4、POST方法,bodyType为application/x-www-form-urlencoded,不带queryParams,带bodyParams;
请求
curl -H 'Content-Type:application/x-www-form-urlencoded' -d 'key=value' 'http://localhost:8089/my/url'

打印JSON.toJSONString(requestMetadata)

{
    "body": "",
    "contentLength": 9,
    "contentType": "application/x-www-form-urlencoded",
    "headerNames": {
        "content-length": "9",
        "host": "localhost:8089",
        "content-type": "application/x-www-form-urlencoded",
        "user-agent": "curl/7.54.0",
        "accept": "*/*"
    },
    "method": "POST",
    "parameterMap": {
        "key": "value"
    },
    "protocol": "HTTP/1.1",
    "scheme": "http",
    "serverName": "localhost",
    "serverPort": "8089",
    "servletPath": "/my/url",
    "uri": "/my/url",
    "url": "http://localhost:8089/my/url"
}

注意:bodyType为application/x-www-form-urlencoded时,body中的key/value形式的参数,存到了以parameterMap为 key 的 JSONObject中。

5、POST方法,bodyType为application/x-www-form-urlencoded,带queryParams,不带bodyParams;
请求
curl -H 'Content-Type:application/x-www-form-urlencoded' -d '' 'http://localhost:8089/my/url?key=value'

打印JSON.toJSONString(requestMetadata)

{
    "body": "",
    "contentLength": 0,
    "contentType": "application/x-www-form-urlencoded",
    "headerNames": {
        "content-length": "0",
        "host": "localhost:8089",
        "content-type": "application/x-www-form-urlencoded",
        "user-agent": "curl/7.54.0",
        "accept": "*/*"
    },
    "method": "POST",
    "parameterMap": {
        "key": "value"
    },
    "protocol": "HTTP/1.1",
    "queryString": "key=value",
    "scheme": "http",
    "serverName": "localhost",
    "serverPort": "8089",
    "servletPath": "/my/url",
    "uri": "/my/url",
    "url": "http://localhost:8089/my/url"
}

注意:bodyType为application/x-www-form-urlencoded时,queryParams参数,存到了以parameterMap为 key 的 JSONObject中。

6、POST方法,bodyType为application/x-www-form-urlencoded,带queryParams,带bodyParams;
请求
curl -H 'Content-Type:application/x-www-form-urlencoded' -d 'key1=value1' 'http://localhost:8089/my/url?key2=value2'

打印JSON.toJSONString(requestMetadata)

{
    "body": "",
    "contentLength": 11,
    "contentType": "application/x-www-form-urlencoded",
    "headerNames": {
        "content-length": "11",
        "host": "localhost:8089",
        "content-type": "application/x-www-form-urlencoded",
        "user-agent": "curl/7.54.0",
        "accept": "*/*"
    },
    "method": "POST",
    "parameterMap": {
        "key1": "value1",
        "key2": "value2"
    },
    "protocol": "HTTP/1.1",
    "queryString": "key2=value2",
    "scheme": "http",
    "serverName": "localhost",
    "serverPort": "8089",
    "servletPath": "/my/url",
    "uri": "/my/url",
    "url": "http://localhost:8089/my/url"
}

注意:bodyType为application/x-www-form-urlencoded时,queryParams参数 和 body中的key/value形式的参数,存到了以parameterMap为 key 的 JSONObject中。

7、POST方法,bodyType为application/json,不带queryParams,不带bodyParams;
请求
curl -H 'Content-Type:application/json' -d '' 'http://localhost:8089/my/url'

打印JSON.toJSONString(requestMetadata)

{
    "body": "",
    "contentLength": 0,
    "contentType": "application/json",
    "headerNames": {
        "content-length": "0",
        "host": "localhost:8089",
        "content-type": "application/json",
        "user-agent": "curl/7.54.0",
        "accept": "*/*"
    },
    "method": "POST",
    "parameterMap": {
    },
    "protocol": "HTTP/1.1",
    "scheme": "http",
    "serverName": "localhost",
    "serverPort": "8089",
    "servletPath": "/my/url",
    "uri": "/my/url",
    "url": "http://localhost:8089/my/url"
}

8、POST方法,bodyType为application/json,不带queryParams,带bodyParams;
请求
curl -H 'Content-Type:application/json' -d '{"key": "value"}' 'http://localhost:8089/my/url'

打印JSON.toJSONString(requestMetadata)

{
    "body": "{\"key\": \"value\"}",
    "contentLength": 16,
    "contentType": "application/json",
    "headerNames": {
        "content-length": "16",
        "host": "localhost:8089",
        "content-type": "application/json",
        "user-agent": "curl/7.54.0",
        "accept": "*/*"
    },
    "method": "POST",
    "parameterMap": {

    },
    "protocol": "HTTP/1.1",
    "scheme": "http",
    "serverName": "localhost",
    "serverPort": "8089",
    "servletPath": "/my/url",
    "uri": "/my/url",
    "url": "http://localhost:8089/my/url"
}

注意:bodyType为application/json时,body中的key/value形式的参数 或 json形式的参数,以字符串的形式存到了body中。

9、POST方法,bodyType为application/json,带queryParams,不带bodyParams;
请求
curl -H 'Content-Type:application/json' -d '' 'http://localhost:8089/my/url?key=value'

打印JSON.toJSONString(requestMetadata)

{
    "body": "",
    "contentLength": 0,
    "contentType": "application/json",
    "headerNames": {
        "content-length": "0",
        "host": "localhost:8089",
        "content-type": "application/json",
        "user-agent": "curl/7.54.0",
        "accept": "*/*"
    },
    "method": "POST",
    "parameterMap": {
        "key": "value"
    },
    "protocol": "HTTP/1.1",
    "queryString": "key=value",
    "scheme": "http",
    "serverName": "localhost",
    "serverPort": "8089",
    "servletPath": "/my/url",
    "uri": "/my/url",
    "url": "http://localhost:8089/my/url"
}

注意:bodyType为application/json时,queryParams中的key/value形式的参数,存到了以parameterMap为 key 的 JSONObject中。

10、POST方法,bodyType为application/json,带queryParams,带bodyParams;
请求
curl -H 'Content-Type:application/json' -d '{"key": "value"}' 'http://localhost:8089/my/url?key2=value2'

打印JSON.toJSONString(requestMetadata)

{
    "body": "{\"key\": \"value\"}",
    "contentLength": 11,
    "contentType": "application/json",
    "headerNames": {
        "content-length": "11",
        "host": "localhost:8089",
        "content-type": "application/json",
        "user-agent": "curl/7.54.0",
        "accept": "*/*"
    },
    "method": "POST",
    "parameterMap": {
        "key2": "value2"
    },
    "protocol": "HTTP/1.1",
    "queryString": "key2=value2",
    "scheme": "http",
    "serverName": "localhost",
    "serverPort": "8089",
    "servletPath": "/my/url",
    "uri": "/my/url",
    "url": "http://localhost:8089/my/url"
}

注意:bodyType为application/json时,queryParams中的key/value形式的参数,存到了以parameterMap为 key 的 JSONObject中。而body中的key/value形式的参数 或 json形式的参数,以字符串的形式存到了body中。


总结

通过这些实验,主要还是想了解 queryParams(无论GET方法还是POST方法)和bodyType为Content-Type:application/x-www-form-urlencoded时的bodyParams会怎么存储,现在知道了,都会存到了以parameterMap为 key 的 JSONObject中,这样我们就不用自己去区分解析了,做工具平台的时候非常方便。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值