前言
我们在进行请求进行拦截的时候经常会碰上这样一个问题,我们想要在拦截器filter中获取request的请求,如果使用请求中默认的getInputStream()方法或者getReader()方法获取数据,但是在后面的Controller中使用@ResquestBody注解,我们读取不到request的body中的值,这是因为request的body中的数据只能通过getInputStream()和getReader()方法读取一次,要解决这个问题,我们要对重写request请求的getInputStream()和getReader()方法。
获取POST请求的输入流,并修改
一般在POST请求中我们携带的信息是application/json格式的。在一些场景中我们要对这些POST请求中的application/json信息进行获取、解析。
先看代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
| public class XssRequestWrapper extends HttpServletRequestWrapper {
private static Policy policy = null;
private static final AntiSamy antiSamy = new AntiSamy();
private String body;
private Map<String, String> parameters = new HashMap<String, String>();
private byte[] bytes;
private boolean isInit = false;
private static final String DEFAULT_CHARSET_NAME = "UTF-8"; private ObjectMapper objectMapper = new ObjectMapper();
public XssRequestWrapper(HttpServletRequest request) throws IOException { super(request); try { String contentType = request.getContentType(); if(contentType.contains(";")){ contentType = contentType.substring(0,contentType.indexOf(";")); } initBytes(); if(contentType.equals(MediaType.APPLICATION_JSON_VALUE)){ parseJsonParameters(); } } catch (IOException e) { throw new RuntimeException("IOException", e); } }
private void initBytes() throws IOException { isInit = true; StringBuilder buffer = new StringBuilder(); BufferedReader reader = this.getHttpServletRequest().getReader(); String line; while ((line = reader.readLine()) != null) { buffer.append(line); } body = buffer.toString(); bytes = body.getBytes(DEFAULT_CHARSET_NAME); }
private void parseJsonParameters() throws IOException { StringBuilder stringBuilder = new StringBuilder("{"); if (null != body && body.length() > 0) { JsonNode node = objectMapper.readTree(body); Iterator<String> fieldNames = node.getFieldNames(); for (; fieldNames.hasNext();) { String key = fieldNames.next(); String value = node.get(key).toString(); if (value.length() > 2 && value.startsWith("\"")) { String valueTemp = value.substring(1,value.length()-1); valueTemp = StringEscapeUtils.unescapeJava(valueTemp); valueTemp = StringEscapeUtils.escapeJava(valueTemp); valueTemp = "\"" + valueTemp + "\""; parameters.put(key, valueTemp); } else { parameters.put(key, value); } } } for(String key:parameters.keySet()){ String value = parameters.get(key); stringBuilder.append("\""+key+"\":"+value+","); } stringBuilder.deleteCharAt(stringBuilder.length()-1); stringBuilder.append("}"); try { bytes = stringBuilder.toString().getBytes(DEFAULT_CHARSET_NAME); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } private HttpServletRequest getHttpServletRequest() { return (HttpServletRequest) super.getRequest(); }
@Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); }
@Override public ServletInputStream getInputStream() throws IOException { if (!isInit) initBytes(); final ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
return new ServletInputStream() { @Override public int read() throws IOException { return bais.read(); } }; }
|
总结
分析:获取Post请求输入流,又保证数据不丢失的步骤如下:
- 继承父类的构造方法,在自己的方法中进行数据的初始化
- 数据的初始化就是,获取输入流,写入本类的char[] bytes中
- 重新getInputStream()方法和getReader()方法,其中getInputStream()方法直接读取bytes字节流信息
- 解析application/json数据,利用JsonNode类