通过自定义过滤器,拦截请求,存储请求相关数据,便于其他地方使用
- 自定义bean,存储请求相关数据(可自行扩展)
/**
* Created by ypc
* 2023/6/27 14:52
* Description:自定义bean,存储请求相关数据(可自行扩展)
*/
@Accessors(chain = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RequestInfo {
/**
* 请求ip
*/
private String ip;
/**
* http 头的Referer
*/
private String referer;
/**
* http 头的user-agent
*/
private String userAgent;
}
-
请求工具类
利用ThreadLocal将请求数据封装在当前线程中。
/**
* Created by ypc
* 2023/6/27 15:12
* Description:TODO
*/
public class RequestContext {
private static final RequestInfo EMPTY = new RequestInfo();
/**
* 用于存储请求相关数据
*/
private static final ThreadLocal<RequestInfo> threadLocal = new ThreadLocal<>();
/**
* 设置请求相关数据
* @param requestInfo
*/
public static void setRequestInfo(RequestInfo requestInfo) {
if (requestInfo != null) {
threadLocal.set(requestInfo);
}
}
/**
* 获取请求相关数据
* @return
*/
public static RequestInfo getRequestInfo() {
return Optional.ofNullable(threadLocal.get()).orElse(EMPTY);
}
/**
* 清除请求相关数据
*/
public static void remove() {
threadLocal.remove();
}
/**
* 获取请求ip
* @return
*/
public static String getIp() {
return getRequestInfo().getIp();
}
/**
* 获取请求user-agent
* @return
*/
public static String getUserAgent() {
return getRequestInfo().getUserAgent();
}
/**
* 获取请求referer
* @return
*/
public static String getReferer() {
return getRequestInfo().getReferer();
}
}
-
自定义请求过滤器
实现OncePerRequestFilter接口,该接口的doFilterInternal方法可以实现对请求的过滤
效果:基于线程,存储当前请求的相关数据
/**
* Created by ypc
* 2023/6/27 14:50
* Description:自定义请求过滤器
* 实现OncePerRequestFilter接口,该接口的doFilterInternal方法可以实现对请求的过滤
* 效果:基于线程,存储当前请求的相关数据
*/
public class HttpContextFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
try {
String referer = httpServletRequest.getHeader(HttpHeaderNames.REFERER.toString());
String userAgent = httpServletRequest.getHeader(HttpHeaderNames.USER_AGENT.toString());
String ip = getIPAddress(httpServletRequest);
RequestInfo context = new RequestInfo(ip, referer, userAgent);
RequestContext.setRequestInfo(context);
filterChain.doFilter(httpServletRequest, httpServletResponse);
} finally {
RequestContext.remove();
}
}
/**
* 获取请求ip
* @param request
* @return
*/
private String getIPAddress(HttpServletRequest request) {
String ip = null;
//X-Forwarded-For:Squid 服务代理
String ipAddresses = request.getHeader("X-Forwarded-For");
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//Proxy-Client-IP:apache 服务代理
ipAddresses = request.getHeader("Proxy-Client-IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//WL-Proxy-Client-IP:weblogic 服务代理
ipAddresses = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//HTTP_CLIENT_IP:有些代理服务器
ipAddresses = request.getHeader("HTTP_CLIENT_IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//X-Real-IP:nginx服务代理
ipAddresses = request.getHeader("X-Real-IP");
}
//有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
if (ipAddresses != null && ipAddresses.length() != 0) {
ip = ipAddresses.split(",")[0];
}
//还是不能获取到,最后再通过request.getRemoteAddr();获取
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
ip = request.getRemoteAddr();
}
return ip;
}
}
- 测试
@RequestMapping(value = "/hi_test")
public String hiTest(){
return RequestContext.getIp() + "\n\n" + RequestContext.getUserAgent();
}
-
请求效果测试
使用postman模拟请求,查看返回效果

博客介绍了利用Java和Spring相关技术,通过自定义过滤器拦截请求,存储请求相关数据。自定义bean存储数据,利用ThreadLocal封装请求数据到当前线程。实现OncePerRequestFilter接口进行请求过滤,最后使用Postman模拟请求进行效果测试。

被折叠的 条评论
为什么被折叠?



