在公司写验签的时候,遇到了一个问题:
用post请求,application/json形式的时候,request要想获取参数,只能用流的形式,但是这样造成的问题是,我把参数从流中拿出来消耗之后,request中就没有了参数的信息,这样就达不到验签(验证请求是否正确,不会操作请求的任何信息,请求照样向后传递)的效果了。所以从网上找到了一个解决方法,并用过滤器来实现这个验签,放弃用拦截器实现的想法,就成了。在这里给大家分享出来,希望可以有帮助。
文章写的很好,相信大家可以理解。
文章如下:
获取请求对象中的数据流,通过解析流信息来获取提交的内容;代码示例如下:
- /**
- * 获取请求Body
- *
- * @param request
- * @return
- */
- public static String getBodyString(ServletRequest request) {
- StringBuilder sb = new StringBuilder();
- InputStream inputStream = null;
- BufferedReader reader = null;
- try {
- inputStream = request.getInputStream();
- reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
- String line = "";
- while ((line = reader.readLine()) != null) {
- sb.append(line);
- }
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- if (inputStream != null) {
- try {
- inputStream.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- if (reader != null) {
- try {
- reader.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- return sb.toString();
- }
-
通过这种简单的解析方式,将http请求中的body解析成 字符串的形式;然后再对字符串的格式进行业务解析;
这种处理方式的优点是:能解析 出content-Type 为 application/x-www-form-urlencoded ,application/json , text/xml 这三种提交方式的 数据
但是这种方式有一个很大的缺点:那就是当从请求中获取流以后,流被filter中的这个 inputStreamToString(InputStream in) 这个方法处理后就被“消耗”了,这会导致,chain.doFilter(request, res)这个链在传递 request对象的时候,里面的请求流为空,导致责任链模式下,其他下游的链无法获取请求的body,从而导致程序无法正常运行,这也使得我们的这个filter虽然可以获取请求信息,但是它会导致整个应用程序不可用,那么它也就失去了意义;
针对缺陷:流一旦被读取,就无法向下传递整个问题,有如下解决方案;
解决思路如下:将取出来的字符串,再次转换成流,然后把它放入到新request 对象中,在chain.doFiler方法中 传递新的request对象;要实现这种思路,需要自定义一个类
继承HttpServletRequestWrapper,然后重写public BufferedReader getReader()方法,public ServletInputStream getInputStream()方法;(这两个方法的重写实现逻辑如下:getInputStream()方法中将body体中的字符串转换为字节流(它实质上返回的是一个ServletInputStream 对象);然后通过getReader()调用---->getInputStream()方法;),继承实现重写逻辑以后,在自定义分filter(VersionCheckFilter)中,使用自定义的HttpServletRequestWrapper(BodyReaderHttpServletRequestWrapper)将原始的HttpServletRequest对象进行再次封装;再通过BodyReaderHttpServletRequestWrapper对象去做dofilter(req,res)的req对象;
涉及的三个类的代码如下:
自定义的HttpServletRequestWrapper
- import java.io.BufferedReader;
- import java.io.ByteArrayInputStream;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.nio.charset.Charset;
- import java.util.Enumeration;
- import javax.servlet.ServletInputStream;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletRequestWrapper;
- import com.yt.util.HttpHelper;
- public class BodyReaderHttpServletRequestWrapper extends
- HttpServletRequestWrapper {
- private final byte[] body;
- public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
- super(request);
- System.out.println("-------------------------------------------------");
- Enumeration e = request.getHeaderNames() ;
- while(e.hasMoreElements()){
- String name = (String) e.nextElement();
- String value = request.getHeader(name);
- System.out.println(name+" = "+value);
- }
- body = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8"));
- }
- @Override
- public BufferedReader getReader() throws IOException {
- return new BufferedReader(new InputStreamReader(getInputStream()));
- }
- @Override
- public ServletInputStream getInputStream() throws IOException {
- final ByteArrayInputStream bais = new ByteArrayInputStream(body);
- return new ServletInputStream() {
- @Override
- public int read() throws IOException {
- return bais.read();
- }
- };
- }
- @Override
- public String getHeader(String name) {
- return super.getHeader(name);
- }
- @Override
- public Enumeration<String> getHeaderNames() {
- return super.getHeaderNames();
- }
- @Override
- public Enumeration<String> getHeaders(String name) {
- return super.getHeaders(name);
- }
- }
2、辅助类
HttpHelper
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.nio.charset.Charset;
- import javax.servlet.ServletRequest;
- public class HttpHelper {
- /**
- * 获取请求Body
- *
- * @param request
- * @return
- */
- public static String getBodyString(ServletRequest request) {
- StringBuilder sb = new StringBuilder();
- InputStream inputStream = null;
- BufferedReader reader = null;
- try {
- inputStream = request.getInputStream();
- reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
- String line = "";
- while ((line = reader.readLine()) != null) {
- sb.append(line);
- }
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- if (inputStream != null) {
- try {
- inputStream.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- if (reader != null) {
- try {
- reader.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- return sb.toString();
- }
- }
3、自定义的filter
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.PrintWriter;
- import java.net.URL;
- import java.net.URLDecoder;
- import java.util.Map;
- import javax.servlet.Filter;
- import javax.servlet.FilterChain;
- import javax.servlet.FilterConfig;
- import javax.servlet.ServletException;
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.xml.crypto.URIDereferencer;
- import com.yt.util.HttpHelper;
- import com.yt.util.JsonHelper;
- public class VersionCheckFilter implements Filter {
- @Override
- public void destroy() {
- }
- @Override
- public void doFilter(ServletRequest req, ServletResponse res,
- FilterChain chain) throws IOException, ServletException {
- HttpServletRequest hreq = (HttpServletRequest) req;
- String uri = hreq.getRequestURI();
- if(uri.contains("uploadImageServlet")){
- //图像上传的请求,不做处理
- chain.doFilter(req, res);
- }else{
- String reqMethod = hreq.getMethod();
- if("POST".equals(reqMethod)){
- PrintWriter out = null;
- HttpServletResponse response = (HttpServletResponse) res;
- response.setCharacterEncoding("UTF-8");
- response.setContentType("application/json; charset=utf-8");
- /* String requestStr = this.inputStreamToString(hreq.getInputStream());
- String[] arrs = requestStr.split("&");
- for (String strs : arrs) {
- String[] strs2 = strs.split("=");
- for (int i = 0; i < strs2.length; i++) {
- if (strs2[0].equals("param")) {
- if (strs2[1] != null &&!strs2[1].equals("")) {
- System.out.println("test=" + strs2[1]);
- }
- }
- }
- }*/
- ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(hreq);
- String body = HttpHelper.getBodyString(requestWrapper);
- //如果是POST请求则需要获取 param 参数
- String param = URLDecoder.decode(body,"utf-8");
- //String param = hreq.getParameter("param");
- //json串 转换为Map
- if(param!=null&¶m.contains("=")){
- param = param.split("=")[1];
- }
- Map paramMap = JsonHelper.getGson().fromJson(param, Map.class);
- Object obj_clientversion = paramMap.get("clientVersion");
- String clientVersion = null;
- if(obj_clientversion != null){
- clientVersion = obj_clientversion.toString();
- System.out.println(clientVersion);
- /*try {
- out = response.getWriter();
- Map remap = new HashMap<String, Object>();
- remap.put("code", 9);
- remap.put("message", Constant.SYSTEM_ERR_DESC);
- out.append(JsonHelper.getGson().toJson(remap));
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- if (out != null) {
- out.close();
- }
- }*/
- chain.doFilter(requestWrapper, res);
- }else{
- chain.doFilter(requestWrapper, res);
- }
- }else{
- //get请求直接放行
- chain.doFilter(req, res);
- }
- }
- }
- @Override
- public void init(FilterConfig arg0) throws ServletException {
- }
- /*public String inputStreamToString(InputStream in) throws IOException {
- StringBuffer out = new StringBuffer();
- byte[] b = new byte[4096];
- for (int n; (n = in.read(b)) != -1;) {
- out.append(new String(b, 0, n));
- }
- return out.toString();
- }*/
- }