松江专业做网站公司,专业网站seo推广,青海省网站建设公司,做公司网站合同文章目录 一、最终使用效果#xff08;ClientIp 注解获取#xff09;二、实现代码1.注解2.方法参数解析器#xff08;Resolver#xff09;3.全局增加Resolver配置 Spring 框架没有现成工具可以方便提取客户端的IP地址#xff0c;普遍做法就是通过 HttpServletRequest 的 g… 文章目录 一、最终使用效果ClientIp 注解获取二、实现代码1.注解2.方法参数解析器Resolver3.全局增加Resolver配置 Spring 框架没有现成工具可以方便提取客户端的IP地址普遍做法就是通过 HttpServletRequest 的 getRemoteAddr 方法获取IP地址。 存在以下问题 1.proxy部分客户端使用代理后此方法返回的是代理网络的IP地址非用户真实 IP 2.SLB后台经过负载均衡如阿里云的SLB实例 3方法返回地址是SLB实例 IP并非用户真实 IP 3.环回地址在本地测试时获取到的是ipv4127.0.0.1 或者 ipv60:0:0:0:0:0:0:1并非本机分配地址 4.代码简洁与耦合每次获取地址都需要注入 HttpServletRequest 再提取使用 Spring WebFlux 1 而不是Spring MVC没有此对象可用 5.获取地址可能是IPv6 地址长度不同数据库需要兼容处理适配以后 IPv6需求 问题解决 1.proxy 经过代理后通常可用通过 http header 的 Proxy-Client-IP 获取用户真实 IP地址 2.SLB经过SLB实例后可通过 http header 的 X-Forwarded-For 获取用户真实IP 3.环回地址如果是环回地址则根据网卡取本机配置的IP如192.168.199.123 等 4.代码简洁与耦合实现参数解析器使用注解方式获取IP如 ClientIp 5.不同版本 IP 长度不同取最长作为数据库存储长度47最长 一、最终使用效果ClientIp 注解获取
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;Slf4j
RestController
RequestMapping(/test)
EnableAutoConfiguration
public class OrderController {GetMapping(/hello)ResponseBodyResponseStatus(HttpStatus.OK)public String hello(ClientIp String ip) {return hello, ip ip;}
}二、实现代码 注下面为 Spring MVC 下的实现代码如需在Spring webFlux 下使用同理实现下面方法、配置即可 org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver org.springframework.web.reactive.config.WebFluxConfigurer 1.注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;Target(ElementType.PARAMETER)
Retention(RetentionPolicy.RUNTIME)
public interface ClientIp {}2.方法参数解析器Resolver
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;import javax.servlet.ServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;public class ClientIpResolver implements HandlerMethodArgumentResolver {private static final String[] IP_HEADER_CANDIDATES {X-Forwarded-For,Proxy-Client-IP,WL-Proxy-Client-IP,HTTP_X_FORWARDED_FOR,HTTP_X_FORWARDED,HTTP_X_CLUSTER_CLIENT_IP,HTTP_CLIENT_IP,HTTP_FORWARDED_FOR,HTTP_FORWARDED,HTTP_VIA,REMOTE_ADDR};Overridepublic boolean supportsParameter(MethodParameter param) {return param.getParameterType().equals(String.class) param.hasParameterAnnotation(ClientIp.class);}Overridepublic Object resolveArgument(MethodParameter parameter,ModelAndViewContainer mavContainer,NativeWebRequest webRequest,WebDataBinderFactory binderFactory) {// 提取header得到IP地址列表多重代理场景取第一个IPfor (String header : IP_HEADER_CANDIDATES) {String ipList webRequest.getHeader(header);if (ipList ! null ipList.length() ! 0 !unknown.equalsIgnoreCase(ipList)) {return ipList.split(,)[0];}}// 没有经过代理或者SLB直接 getRemoteAddr 方法获取IPString ip ((ServletRequest) webRequest.getNativeRequest()).getRemoteAddr();// 如果是本地环回IP则根据网卡取本机配置的IPif (127.0.0.1.equals(ip) || 0:0:0:0:0:0:0:1.equals(ip)) {try {InetAddress inetAddress InetAddress.getLocalHost();return inetAddress.getHostAddress();} catch (UnknownHostException e) {e.printStackTrace();return ip;}}return ip;}
}3.全局增加Resolver配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import java.util.List;Configuration
public class NetWebMvcConfigurer implements WebMvcConfigurer {Overridepublic void addArgumentResolvers(ListHandlerMethodArgumentResolver resolvers) {resolvers.add(clientIpResolver());}Beanpublic ClientIpResolver clientIpResolver() {return new ClientIpResolver();}
}