|
|
@@ -0,0 +1,75 @@
|
|
|
+package common.utils;
|
|
|
+
|
|
|
+import com.jfinal.core.Controller;
|
|
|
+import com.jfinal.kit.StrKit;
|
|
|
+
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
+
|
|
|
+public class IpAddressUtil {
|
|
|
+ /**
|
|
|
+ * 在 Controller 中获取请求方的公网 IP 地址
|
|
|
+ * 考虑了多层代理(CDN, 负载均衡器, 反向代理等)的情况
|
|
|
+ *
|
|
|
+ * @param controller JFinal的Controller实例
|
|
|
+ * @return 客户端公网IP地址,如果获取失败则返回 null 或空字符串
|
|
|
+ */
|
|
|
+ public static String getClientIpAddress(Controller controller) {
|
|
|
+ return getClientIpAddress(controller.getRequest());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取请求方的公网 IP 地址
|
|
|
+ * 考虑了多层代理(CDN, 负载均衡器, 反向代理等)的情况
|
|
|
+ *
|
|
|
+ * @param request HttpServletRequest 请求对象
|
|
|
+ * @return 客户端公网IP地址,如果获取失败则返回 null 或空字符串
|
|
|
+ */
|
|
|
+ public static String getClientIpAddress(HttpServletRequest request) {
|
|
|
+ if (request == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 顺序检查各种可能的代理Header
|
|
|
+ String ip = request.getHeader("X-Forwarded-For");
|
|
|
+ if (StrKit.notBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
|
|
|
+ // X-Forwarded-For 可能包含多个 IP 地址,用逗号分隔,第一个通常是真实客户端IP
|
|
|
+ int commaOffset = ip.indexOf(',');
|
|
|
+ if (commaOffset > 0) {
|
|
|
+ ip = ip.substring(0, commaOffset);
|
|
|
+ }
|
|
|
+ return ip.trim();
|
|
|
+ }
|
|
|
+
|
|
|
+ ip = request.getHeader("Proxy-Client-IP");
|
|
|
+ if (StrKit.notBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
|
|
|
+ return ip.trim();
|
|
|
+ }
|
|
|
+
|
|
|
+ ip = request.getHeader("WL-Proxy-Client-IP");
|
|
|
+ if (StrKit.notBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
|
|
|
+ return ip.trim();
|
|
|
+ }
|
|
|
+
|
|
|
+ ip = request.getHeader("HTTP_CLIENT_IP");
|
|
|
+ if (StrKit.notBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
|
|
|
+ return ip.trim();
|
|
|
+ }
|
|
|
+
|
|
|
+ ip = request.getHeader("HTTP_X_FORWARDED_FOR"); // 有些代理会使用此Header
|
|
|
+ if (StrKit.notBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
|
|
|
+ int commaOffset = ip.indexOf(',');
|
|
|
+ if (commaOffset > 0) {
|
|
|
+ ip = ip.substring(0, commaOffset);
|
|
|
+ }
|
|
|
+ return ip.trim();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 最终回退到 Servlet API 的默认获取方式
|
|
|
+ // 这个通常是直接连接到你应用服务器的代理服务器的IP,而不是客户端真实IP
|
|
|
+ ip = request.getRemoteAddr();
|
|
|
+ return ip;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 考虑到可能会有 IPv6 地址,但通常情况下我们关心 IPv4。
|
|
|
+ // 如果需要专门处理 IPv6,可以在匹配 IP 地址时进行正则判断。
|
|
|
+}
|