Spring框架获取用户真实IP(注解式)
文章目录
- 一、最终使用效果(@ClientIp 注解获取)
- 二、实现代码
- 1.注解
- 2.方法参数解析器(Resolver)
- 3.全局增加Resolver配置
Spring 框架没有现成工具可以方便提取客户端的IP地址,普遍做法就是通过 HttpServletRequest 的 getRemoteAddr 方法获取IP地址。
存在以下问题:
1.proxy:部分客户端使用代理后此方法返回的是代理网络的IP地址,非用户真实 IP
2.SLB:后台经过负载均衡,如阿里云的SLB实例 3,方法返回地址是SLB实例 IP,并非用户真实 IP
3.环回地址:在本地测试时获取到的是ipv4:127.0.0.1 或者 ipv6:0: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")@ResponseBody@ResponseStatus(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) &¶m.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(List<HandlerMethodArgumentResolver> resolvers) {resolvers.add(clientIpResolver());}@Beanpublic ClientIpResolver clientIpResolver() {return new ClientIpResolver();}
}
相关文章:
Spring框架获取用户真实IP(注解式)
文章目录 一、最终使用效果(ClientIp 注解获取)二、实现代码1.注解2.方法参数解析器(Resolver)3.全局增加Resolver配置 Spring 框架没有现成工具可以方便提取客户端的IP地址,普遍做法就是通过 HttpServletRequest 的 g…...

利用 IDEA IDE 的轻量编辑模式快速查看和编辑工程外的文本文件
作为程序员, 我们都知道 IDE 的很好用的, 它的文本编辑器功能也非常的强大, 用起来非常便捷. 在长年累月的使用中, 我们也变得对其非常熟悉, 以致于使用起其它简单地轻量级的文本编辑器来, 比如什么记事本, Notepad, UltraEdit 等等呀, 觉得既不方便又不熟悉. 关键是很多的操作…...

MyBatisx代码生成
MyBatisx代码生成 1.创建数据库表 CREATE TABLE sys_good (good_id int(11) NOT NULL,good_name varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,good_desc varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,PRIMARY KEY (good_id) ) ENGINEInnoDB DEFAULT CHA…...
【日记】文章更新计划
首发博客地址[1] 状态 这两天也没加班,也没干什么活。不知道怎么回事,到家就想睡觉。所以这两天睡得很早,基本上 11 点之前就睡了,文章也就鸽了两天。 计划 今早起来感觉还是要自律,我写文章的初衷是为了学习。基于这个…...

UML用例图三种关系(重点)-架构真题(十七)
某项目包括A、B、C、D四道工序,各道工序之间的衔接关系、正常进度下各工序所需的时间和直接费用、赶工进度下所需的时间和直接费用如下表所示。该项目每天需要间接费用为4.5万元,根据此表,最低成本完成需要()天。&…...
分层解耦介绍
三层架构 Controller:控制层,接受前端发送的请求,对请求进行处理,并响应数据 service:业务逻辑层,处理具体业务逻辑 dao:数据访问层,负责数据访问操作,包括数据的增、删、…...

Nginx百科之gzip压缩、黑白名单、防盗链、零拷贝、跨域、双机热备
引言 早期的业务都是基于单体节点部署,由于前期访问流量不大,因此单体结构也可满足需求,但随着业务增长,流量也越来越大,那么最终单台服务器受到的访问压力也会逐步增高。时间一长,单台服务器性能无法跟上业…...

git通过fork-merge request实现多人协同
一、问题 对于一个项目,如果需要多人协同开发,大家都在原始仓库中进行修改提交,经常会发生冲突,而且一不小心会把别人的代码内容覆盖掉。为了避免这样的问题,git提供了fork-merge request这样的协同方式。 二、仓库框…...

元素居中的方法总结
目录 垂直居中 行内元素垂直居中 单行文本垂直居中 1.line-height: 200px; 多行文本垂直居中 1.tablevertical-align:middle 块级元素垂直居中 1.display: flex;align-items: center; 2.使用position top margin-top 水平居中 行内元素水平居中 1.text-align:cente…...
后端面试话术集锦第一篇:spring面试话术
这是后端面试集锦第一篇博文——spring面试话术❗❗❗ 1. 介绍一下spring 关于spring,我们平时做项目一直都在用,不管是使用ssh还是使用ssm,都可以整合。 Spring主要就三点,也就是核心思想: IOC控制反转 DI依赖注入 AOP切面编程 我先说说IOC吧,IOC就是spring里的控制反…...

elasticsearch8.9.1集群搭建
目录 1.官网文档 2.安装步骤 2.1 环境准备 2.2 添加用户 2.3 修改文件profile文件 2.4 修改elasticsearch.yml 2.5 修改 sysctl.conf 3.启动 3.1 切换到kibana 3.2 启动elasticsearch 3.3 启动kibana 3.4 验证节点情况 1.官网文档 elasticsearch文档:ht…...

前端调用电脑摄像头
项目中需要前端调用,所以做了如下操作 先看一下效果吧 主要是基于vue3,通过canvas把画面转成base64的形式,然后是把base64转成 file文件,最后调用了一下上传接口 以下是代码 进入页面先调用一下摄像头 navigator.mediaDevices.ge…...
网络编程day1——进程间通信-socket套接字
基本特征:socket是一种接口技术,被抽象了一种文件操作,可以让同一计算机中的不同进程之间通信,也可以让不同计算机中的进程之间通信(网络通信) 本地进程间通信编程模型: 进程A …...

Android-关于页面卡顿的排查工具与监测方案
作者:一碗清汤面 前言 关于卡顿这件事已经是老生常谈了,卡顿对于用户来说是敏感的,容易被用户直接感受到的。那么究其原因,卡顿该如何定义,对于卡顿的发生该如何排查问题,当线上用户卡顿时,在线…...

VueX 与Pinia 一篇搞懂
VueX 简介 Vue官方:状态管理工具 状态管理是什么 需要在多个组件中共享的状态、且是响应式的、一个变,全都改变。 例如一些全局要用的的状态信息:用户登录状态、用户名称、地理位置信息、购物车中商品、等等 这时候我们就需要这么一个工…...

指针与空间按钮的交互
文章目录 原理案例:“直线指针”和“点击按钮”的交互1、效果2、步骤 原理 指针不能直接和空间按钮交互,得借助一个中间层——分发器——它分发指针的进入、退出、选择事件,空间按钮自动监听这些事件 案例:“直线指针”和“点击…...

java八股文面试[数据库]——慢查询优化
分析慢查询日志 直接分析慢查询日志, mysql使用explain sql语句进行模拟优化器来执行分析。 oracle使用explain plan for sql语句进行模拟优化器来执行分析。 table | type | possible_keys | key |key_len | ref | rows | Extra EXPLAIN列的解释: ta…...

《Flink学习笔记》——第十章 容错机制
10.1 检查点(Checkpoint) 为了故障恢复,我们需要把之前某个时间点的所有状态保存下来,这份“存档”就是“检查点” 遇到故障重启的时候,我们可以从检查点中“读档”,恢复出之前的状态,这样就可以…...

【LeetCode-中等题】230. 二叉搜索树中第K小的元素
文章目录 题目方法一:层序遍历 集合排序方法二:中序遍历(栈 或者 递归 )方法三(方法二改进):中序遍历(栈 ) 题目 该题最大的特点就是这个树是二叉树: 所以…...

DQL语句的用法(MySQL)
文章目录 前言一、DQL语句间接和语法1、DQL简介2、DQL语法 二、DQL语句使用1、基础查询(1)查询多个字段(2)为字段设置别名(3)去除重复记录 总结 前言 本文主要介绍SQL语句中DQL语句的功能和使用方法&#…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制
目录 节点的功能承载层(GATT/Adv)局限性: 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能,如 Configuration …...

springboot 日志类切面,接口成功记录日志,失败不记录
springboot 日志类切面,接口成功记录日志,失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...
ubuntu22.04 安装docker 和docker-compose
首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...