.后端有拦截器前端怎么取数据?使用getInputStream()、getReader()、getParameterMap()获取请求参数并记录

背景:对已有界面进行操作日志记录,方便日后寻找问题。那就需要在拦截器做日志记录,由于需要获取前端请求参数,实现过程中出现以下问题。

问题:使用getInputStream()或getReader()方法获取请求参数,记录成功,但是后端控制器接收不到请求参数;

原因:HttpServletRequest以流的形式将参数发送至后端,一旦读取后,就会丢失,不会将原有参数发送至控制器。
最终前端报错400,bad request。
.后端有拦截器前端怎么取数据?使用getInputStream()、getReader()、getParameterMap()获取请求参数并记录_第1张图片

解决方案一:当请求头为Content-Type: application/x-www-form-urlencoded时,推荐使用getParameterMap()方法获取请求参数。

public static String getAllParameter(HttpServletRequest request){
		StringBuilder sb = new StringBuilder("{");
		Map<String, String[]> map = request.getParameterMap();
		if(null != map) {
			for (Map.Entry<String, String[]> entry : map.entrySet()) {
				sb.append("\""+entry.getKey()+"\":");
				sb.append("\""+entry.getValue()+"\",");
	        }
		}else {
			sb.append("请求参数为null");
		}
		sb.append("}");
		return sb.toString();
}

解决方案二:当请求头为Content-Type: application/json时,只能使用流读取,getInputStream()或getReader()方法获取请求参数。需要重新封装,才能使用,否则会出现上述问题。

步骤一:重新封装HttpServletRequestWrapper,使得流能重复读取

public class RepeatedlyReadRequestWrapper extends HttpServletRequestWrapper {
    //用于存储读取的流字节
    private final byte[] body;
    public RepeatedlyReadRequestWrapper(HttpServletRequest request)
            throws IOException {
        super(request);
        body = readBytes(request.getReader(), "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 boolean isFinished() {
            return false;
            }
            @Override
            public boolean isReady() {
            return false;
            }
            @Override
            public void setReadListener(ReadListener listener) {
            }
            @Override
            public int read() throws IOException {
            return bais.read();
            }
        };
    }
    private byte[] readBytes(BufferedReader br,String encoding) throws IOException{
        String str = null,retStr="";
        while ((str = br.readLine()) != null) {
            retStr += str;
        }
        if (StringUtils.isNotBlank(retStr)) {
            return retStr.getBytes(Charset.forName(encoding));
        }
        return null;
    }
}

步骤二:添加拦截器,将HttpServletRequest重新封装。初始化上述重新封装HttpServletRequestWrapper。

public class RepeatedlyReadFilter implements Filter {

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

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        logger.debug("将HttpServletRequest重新封装。初始化上述重新封装HttpServletRequestWrapper。");
        ServletRequest requestWrapper = null;
        if (request instanceof HttpServletRequest) {
            requestWrapper = new RepeatedlyReadRequestWrapper((HttpServletRequest) request);
        }
        if (null == requestWrapper) {
            chain.doFilter(request, response);
        } else {
            chain.doFilter(requestWrapper, response);
        }
    }
    @Override
    public void destroy() {
    }
}

步骤三:注册拦截器

@Configuration
public class WebSecurityConfig extends WebMvcConfigurerAdapter
{
    @Bean
    public RedisSessionInterceptor getSessionInterceptor()
    {
        return new RedisSessionInterceptor();
    }
    @Bean
    public FilterRegistrationBean repeatedlyReadFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        RepeatedlyReadFilter repeatedlyReadFilter = new RepeatedlyReadFilter();
        registration.setFilter(repeatedlyReadFilter);
        registration.addUrlPatterns("/*");
        return registration;
    }
}

到此就结束了,之后直接只用request.getInputStream()或request.getReader()
以下是将字节流转成字符串:

public static String btye2Str(HttpServletRequest request){
        StringBuilder sb = new StringBuilder();
        BufferedReader br = null;
        try{
        	br = new BufferedReader(new InputStreamReader(request.getInputStream()));
            String str;
            while ((str = br.readLine()) != null){
                sb.append(str);
            }
            br.close();
            return sb.toString();
        }catch (IOException e){
            e.printStackTrace();
        }finally{
            if (null != br){
                try{
                    br.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
 }

有帮助的小伙伴,帮忙点个赞,蟹蟹

你可能感兴趣的:(java,java,http,https,spring)