资讯专栏INFORMATION COLUMN

java在filter中获取POST请求中request参数以及解决ServletInputStre

OldPanda / 2460人阅读

摘要:想要回去请求中的请求参数,可以直接使用方法。流读取错误流关闭错误这样将获取中的所有格式的参数信息。可以根据需求,进行验签或校验等一系列操作。神奇此时的流已经被读取一次,相当于已经作废,此时请求接口必然是报错的。

想要回去GET请求中的请求参数,可以直接使用request.getParamMap()方法。但是POST请求的requestBody参数就必须使用流的方式来获取。

            BufferedReader reader = null;
            String body = null;
            try {
                reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
                body = IOUtils.read(reader).replaceAll("	|
|
", "");
            } catch (IOException e) {
                logger.error("流读取错误:"+e);
                return;
            }finally {
                if (null != reader){
                    try {
                        reader.close();
                    } catch (IOException e) {
                        logger.error("流关闭错误:"+e);
                    }
                }
            }
            Map paramMap = JSON.parseObject(body);

这样将获取body中的所有json格式的参数信息。可以根据需求,进行验签或校验等一系列操作。但是当我们chain.doFilter(request, response),惊喜的发现接口400了!!
WHAT??!!
嘿嘿o( ̄▽ ̄)d
我们都知道,读取流的时候是有标志的,读取一次移动一次,读取到哪里,移动到哪里,读到最后,返回-1,表示读取完成。再次读取需要重置位置,但是ServletInputStream中是没有重置方法的,也就是说流只能被读取一次。神奇!!Σ(⊙▽⊙"a 此时的流已经被读取一次,相当于已经作废,此时请求接口必然是报错的。
行吧,你既然不让我重复读,那我就把你的流拿过来封装成自己的流,这样我想读多少次就读多少次!ψ(`∇´)ψ
加入jar包:javax.servlet

        
        
            javax.servlet
            javax.servlet-api
            3.1.0
            provided
        

实现HttpServletRequestWrapper类

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.net.URLDecoder;
import java.util.*;

/**
 * @author zhoumin
 * @create 2018-10-31 16:13
 */
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
    private Map paramsMap;

    @Override
    public Map getParameterMap() {
        return paramsMap;
    }

    @Override
    public String getParameter(String name) {// 重写getParameter,代表参数从当前类中的map获取
        String[] values = paramsMap.get(name);
        if (values == null || values.length == 0) {
            return null;
        }
        return values[0];
    }

    @Override
    public String[] getParameterValues(String name) {// 同上
        return paramsMap.get(name);
    }

    @Override
    public Enumeration getParameterNames() {
        return Collections.enumeration(paramsMap.keySet());
    }

    private String getRequestBody(InputStream stream) {
        String line = "";
        StringBuilder body = new StringBuilder();
        int counter = 0;

        // 读取POST提交的数据内容
        BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
        try {
            while ((line = reader.readLine()) != null) {
                if (counter > 0) {
                    body.append("rn");
                }
                body.append(line);
                counter++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return body.toString();
    }

    private HashMap getParamMapFromPost(HttpServletRequest request) {

        String body = "";
        try {
            body = getRequestBody(request.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        HashMap result = new HashMap();

        if (null == body || 0 == body.length()) {
            return result;
        }

        return parseQueryString(body);
    }

    // 自定义解码函数
    private String decodeValue(String value) {
        if (value.contains("%u")) {
            return Encodes.urlDecode(value);
        } else {
            try {
                return URLDecoder.decode(value, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                return "";// 非UTF-8编码
            }
        }
    }

    public HashMap parseQueryString(String s) {
        String valArray[] = null;
        if (s == null) {
            throw new IllegalArgumentException();
        }
        HashMap ht = new HashMap();
        StringTokenizer st = new StringTokenizer(s, "&");
        while (st.hasMoreTokens()) {
            String pair = (String) st.nextToken();
            int pos = pair.indexOf("=");
            if (pos == -1) {
                continue;
            }
            String key = pair.substring(0, pos);
            String val = pair.substring(pos + 1, pair.length());
            if (ht.containsKey(key)) {
                String oldVals[] = (String[]) ht.get(key);
                valArray = new String[oldVals.length + 1];
                for (int i = 0; i < oldVals.length; i++) {
                    valArray[i] = oldVals[i];
                }
                valArray[oldVals.length] = decodeValue(val);
            } else {
                valArray = new String[1];
                valArray[0] = decodeValue(val);
            }
            ht.put(key, valArray);
        }
        return ht;
    }

    private Map getParamMapFromGet(HttpServletRequest request) {
        return parseQueryString(request.getQueryString());
    }

    private final byte[] body; // 报文

    public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        body = readBytes(request.getInputStream());

        // 首先从POST中获取数据
        if ("POST".equals(request.getMethod().toUpperCase())) {
            paramsMap = getParamMapFromPost(this);
        } else {
            paramsMap = getParamMapFromGet(this);
        }

    }

    @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 boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener arg0) {

            }
        };
    }

    private static byte[] readBytes(InputStream in) throws IOException {
        BufferedInputStream bufin = new BufferedInputStream(in);
        int buffSize = 1024;
        ByteArrayOutputStream out = new ByteArrayOutputStream(buffSize);

        byte[] temp = new byte[buffSize];
        int size = 0;
        while ((size = bufin.read(temp)) != -1) {
            out.write(temp, 0, size);
        }
        bufin.close();

        byte[] content = out.toByteArray();
        return content;
    }

}

解码

/**
     * URL 解码, Encode默认为UTF-8.
     */
    public static String urlDecode(String part) {
        try {
            return URLDecoder.decode(part, DEFAULT_URL_ENCODING);
        } catch (UnsupportedEncodingException e) {
            throw new InvalidTokenException(part);
        }
    }

那么上面读取参数的代码修改为:

             ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(
                    (HttpServletRequest) request);
            BufferedReader reader = null;
            String body = null;
            try {
                reader = new BufferedReader(new InputStreamReader(requestWrapper.getInputStream()));
                body = IOUtils.read(reader).replaceAll("	|
|
", "");
            } catch (IOException e) {
                logger.error("流读取错误:"+e);
                return;
            }finally {
                if (null != reader){
                    try {
                        reader.close();
                    } catch (IOException e) {
                        logger.error("流关闭错误:"+e);
                    }
                }
            }
            Map paramMap = JSON.parseObject(body);
            .
            .
            .
            chain.doFilter(requestWrapper, response);

OK!又是打酱油的一天。(づ。◕ᴗᴗ◕。)づ

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/71971.html

相关文章

  • JavaWEB开发15——Listener&Listener

    摘要:创建与销毁对象是发送请求服务器就会创建它,当响应产生时,对象就会销毁。是容器为开发人员提供的对象,它提供了对某一资源的已过滤请求调用链的视图。 一、Listener监听器 Javaweb开发中的监听器,是用于监听web常见对象 HttpServletRequest HttpSession ServletContext 监听它们的创建与销毁 属性变化 session绑...

    RebeccaZhong 评论0 收藏0
  • cors跨域之简单请求与预检请求(发送请求头带令牌token)

    摘要:所以跨域请求分两种简单请求和预检请求。但对于第二个错误,好像没法向第一种那样,将预检请求转变为简单请求,所以,只有寻找方法怎么在后端实现相应的预检请求,来返回一个状态码,告诉浏览器此次跨域请求可以继续。 引子 自从从JAVA伪全栈转前端以来,学习的路上就充满了荆棘(奇葩问题),而涉及前后端分离这个问题,对cors的应用不断增多,暴露出的问题也接踵而至。这两天动手实践基于Token的WE...

    zsy888 评论0 收藏0
  • cors跨域之简单请求与预检请求(发送请求头带令牌token)

    摘要:所以跨域请求分两种简单请求和预检请求。但对于第二个错误,好像没法向第一种那样,将预检请求转变为简单请求,所以,只有寻找方法怎么在后端实现相应的预检请求,来返回一个状态码,告诉浏览器此次跨域请求可以继续。 引子 自从从JAVA伪全栈转前端以来,学习的路上就充满了荆棘(奇葩问题),而涉及前后端分离这个问题,对cors的应用不断增多,暴露出的问题也接踵而至。这两天动手实践基于Token的WE...

    RaoMeng 评论0 收藏0
  • Java后端支付大杂烩之sps.controller(支付请求入口,配置文件)(五)

    摘要:重要的是学习过程,而不是结果。但,结果同样重要,加油。。在这提一点,由于网络原因等异常情况支付平台可能出现多次发送支付结果的情况,通知回调接口商户要注意做好接口幂等,其余的不再多说。 7、sps.controller.base,front. 说明 如果有幸能看到,其实只为自己记录,回头复习用 1、本文项目来自Martin404,自己只是临摹大佬的项目。 2、重要的是学习过程,而不是结...

    Joyven 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<