在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中,这样我们就不用自己去区分解析了,做工具平台的时候非常方便。