请求日志——用于调试开发

一、前言

在请求分发给具体的处理器之前,我们可以通过过滤器和拦截器来截取请求信息,但是藏于body中的参数确不能直接获取,因为在流对象中只允许一次性打开,这就好比你将桶里的水倒干净了,然后把桶交给别人。

常规的处理方案有两种:

       1、将流内容导入另一个流,然后将新的流传递

       2、通过mark()和reset()方法将流内容回流。

最初,我采用第二种方式,却发现依旧存在很多问题,比如mark长度难以确定,无法绕开servletRequest无法二次打开的设定。于是采用第一种办法。

二、如何复制请求流

package com.baye.common.core.filter;


import org.apache.commons.lang.StringUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

/**
 * 复制请求,代替原有request传递给具体处理器
 *
 * @author sunyiran
 * @date 2018-11-27
 */
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
	/**
	 * 利用body存储流内容
	 */
	private final byte[] body;

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

	@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 readListener) {

			}

			@Override
			public int read() throws IOException {
				return bais.read();
			}
		};
	}

	/**
	 * 通过BufferedReader和字符编码集转换成byte数组
	 *
	 * @param br
	 * @return
	 * @throws IOException
	 */
	private byte[] readBytes(BufferedReader br ) throws IOException {
		String str;
		StringBuilder retStr = new StringBuilder();
		while ((str = br.readLine()) != null) {
			retStr.append(str);
		}
		if (StringUtils.isNotBlank(retStr.toString())) {
			return retStr.toString().getBytes(Charset.forName("utf-8"));
		}
		return null;
	}

}


三、如何过滤请求

注意在主类上添加:@ServletComponentScan

package com.baye.common.core.filter;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;


/**
 * todo 上线时关闭
 * @author sunyiran
 * @date 2018-11-27
 */
@WebFilter(urlPatterns = "/*")
public class RequestLogFilter implements Filter{
	private static final Log logger = LogFactory.getLog("RequestLogdFilter");

	@Override
	public void destroy() {

	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
		throws IOException, ServletException {


		ServletRequest requestWrapper = printRequestLog((HttpServletRequest) request);
		if (requestWrapper == null) {
			chain.doFilter(request,response);
		}
		chain.doFilter(requestWrapper, response);
	}

	@Override
	public void init(FilterConfig arg0)  {

	}

	/**
	 * 打印请求详情
	 * @param request
	 * @return
	 * @throws IOException
	 */
	private ServletRequest printRequestLog(HttpServletRequest request) throws IOException {
		Map<String, String[]> params = request.getParameterMap();
		String requestUri = request.getRequestURI();
		String ip = getRemoteHost(request);
		StringBuilder msg = new StringBuilder(
			"\r\n" + ip + "-请求:" + requestUri + "-->[" + request.getMethod() + "]\r\n");

		Enumeration<String> headers = request.getHeaderNames();
		String key = null;
		while (headers.hasMoreElements()) {
			key = headers.nextElement();
			msg.append("\t").append(key).append(":\t\t").append(request.getHeader(key)).append("\r\n");
		}

		msg.append("---------------------------------------------------------------------------------\r\n");
		//如果传递方式为RequestParam
		if (params != null && !params.isEmpty()) {
			msg.append("\tRequestParam:");
			for (Map.Entry<String, String[]> item : params.entrySet()) {
				msg.append("\t").append(item.getKey()).append(":\t\t").append(StringUtils.join(item.getValue(), "/"))
					.append("\r\n");
			}
			logger.info(msg.toString());
			return request;
		}
		//如果传递方式为RequestBody
		msg.append("\r\n\tRequestBody:");
		if (request.getContentLength() > 0) {
			request = new BodyReaderHttpServletRequestWrapper(request);
		}else {
			logger.info(msg.toString());
			return request;
		}
		BufferedReader br = request.getReader();
		String str ;
		StringBuilder retStr= new StringBuilder();
		while ((str = br.readLine()) != null) {
			retStr.append(str);
		}

		msg.append(retStr);
		logger.info(msg.toString());
		return request;
	}

	/**
	 * 获取请求主机地址
	 * @param request
	 * @return
	 */
	public String getRemoteHost(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
	}

}

四、请求测试

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值