0x01:wrapper 类说明
Servlet 的 request body 以及 response body 一旦流被读取了,就无法再次被读取了,因此这对于有些要做拦截业务请求来说,比较麻烦。那么如何处理这个业务场景呢?利用 filter,然后重写 HttpServletRequest 和 HttpServletResponse 包装一层,然后 proceed,最后 response 完之后在把cached 的 body 设置回原始响应。
Spring提供了 ContentCachingRequestWrapper 以及 ContentCachingResponseWrapper 两个类,来解决这类问题。
代码语言:javascript复制ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(response);
读取完 Response body 之后
代码语言:javascript复制wrappedResponse.copyBodyToResponse();
通过这个设置回去,就可以使得接口调用者可以正常接收响应了。
0x02:日志拦截实例
- 继承OncePerRequestFilter,顾名思义该filter能够确保在一次请求只通过一次该 filter
- 实现 Ordered,设置filter的执行顺序,一般设置最低级别执行
package com.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.Ordered;
import org.springframework.web.filter.OncePerRequestFilter;
public class LogFilter extends OncePerRequestFilter implements Ordered {
@Override
public int getOrder() {
// TODO Auto-generated method stub
return 0;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// TODO Auto-generated method stub
}
}
完整代码大致如下
代码语言:javascript复制package com.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;
@Component
public class LogFilter extends OncePerRequestFilter implements Ordered {
@Value("${openLog}")
private boolean openLog;
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE-8;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
ContentCachingRequestWrapper wrappedRequest = null;
ContentCachingResponseWrapper wrappedResponse = null;
try{
if(openLog){
printHender(request);
printCookie(request);
printParameter(request);
wrappedRequest = new ContentCachingRequestWrapper(request);
wrappedResponse = new ContentCachingResponseWrapper(response);
printRequest(wrappedRequest);
printResponse(wrappedResponse);
}else{
filterChain.doFilter(request, response);
}
}finally {
if(wrappedResponse!=null){
wrappedResponse.copyBodyToResponse();
}
}
}
/**
* 打印返回体
*
* @param wrappedRequest
*/
private void printResponse(ContentCachingResponseWrapper wrappedResponse) {
try{
ContentCachingResponseWrapper resp = WebUtils.getNativeResponse(wrappedResponse, ContentCachingResponseWrapper.class);
byte[] responseBody = resp.getContentAsByteArray();
String body = new String(responseBody, resp.getCharacterEncoding());
//TODO 打印
}catch (Exception e) {
// TODO: handle exception
}
}
/**
* 打印请求体
*
* @param wrappedRequest
*/
private void printRequest(ContentCachingRequestWrapper wrappedRequest) {
try{
ContentCachingRequestWrapper req = WebUtils.getNativeRequest(wrappedRequest, ContentCachingRequestWrapper.class);
byte[] reqestBody = req.getContentAsByteArray();
String body = new String(reqestBody, req.getCharacterEncoding());
//TODO 打印
}catch (Exception e) {
// TODO: handle exception
}
}
/**
* 打印参数
*
* @param request
*/
private void printParameter(HttpServletRequest request) {
// TODO Auto-generated method stub
}
/**
* 打印cookie
*
* @param request
*/
private void printCookie(HttpServletRequest request) {
// TODO Auto-generated method stub
}
/**
* 打印请求头
*
* @param request
*/
private void printHender(HttpServletRequest request) {
// TODO Auto-generated method stub
}
}