当前位置: 首页 > news >正文

开源cms建站WordPress文章过滤

开源cms建站,WordPress文章过滤,php淘客网站开发,濮阳网站建设费用前言 场景: 为了限制短信验证码接口的访问次数#xff0c;防止被刷#xff0c;结合Aop和redis根据用户ip对用户限流 1.准备工作 首先我们创建一个 Spring Boot 工程#xff0c;引入 Web 和 Redis 依赖#xff0c;同时考虑到接口限流一般是通过注解来标记#xff0c;而注解…前言 场景: 为了限制短信验证码接口的访问次数防止被刷结合Aop和redis根据用户ip对用户限流 1.准备工作 首先我们创建一个 Spring Boot 工程引入 Web 和 Redis 依赖同时考虑到接口限流一般是通过注解来标记而注解是通过 AOP 来解析的所以我们还需要加上 AOP 的依赖最终的依赖如下 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency然后提前准备好一个 Redis 实例这里我们项目配置好之后直接配置一下 Redis 的基本信息即可比如 spring.redis.hostlocalhost spring.redis.port6379 spring.redis.password1232.限流注解 接下来我们创建一个限流注解我们将限流分为两种情况 1针对当前接口的全局性限流例如该接口可以在 1 分钟内访问 100 次。 2 针对某一个 IP 地址的限流例如某个 IP 地址可以在 1 分钟内访问 100 次 针对这两种情况我们创建一个枚举类 public enum LimitType {/*** 默认策略全局限流*/DEFAULT,/*** 根据请求者IP进行限流*/IP } 接下来我们来创建限流注解 Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) Documented public interface RateLimiter {/*** 限流key*/String key() default rate_limit:;/*** 限流时间,单位秒*/int time() default 60;/*** 限流次数*/int count() default 100;/*** 限流类型*/LimitType limitType() default LimitType.DEFAULT; }第一个参数限流的 key这个仅仅是一个前缀将来完整的 key 是这个前缀再加上接口方法的完整路径共同组成限流 key这个 key 将被存入到 Redis 中。 另外三个参数好理解我就不多说了。 好了将来哪个接口需要限流就在哪个接口上添加 RateLimiter 注解然后配置相关参数即可。 3. 定制或者选择redisTemplate 1. 定制 RedisTemplate(看需要,我使用第二种方案) 在 Spring Boot 中我们其实更习惯使用 Spring Data Redis 来操作 Redis不过默认的 RedisTemplate 有一个小坑就是序列化用的是 JdkSerializationRedisSerializer不知道小伙伴们有没有注意过直接用这个序列化工具将来存到 Redis 上的 key 和 value 都会莫名其妙多一些前缀这就导致你用命令读取的时候可能会出错。 例如存储的时候key 是 namevalue 是 javaboy但是当你在命令行操作的时候get name 却获取不到你想要的数据原因就是存到 redis 之后 name 前面多了一些字符此时只能继续使用 RedisTemplate 将之读取出来。 我们用 Redis 做限流会用到 Lua 脚本使用 Lua 脚本的时候就会出现上面说的这种情况所以我们需要修改 RedisTemplate 的序列化方案。 修改 RedisTemplate 序列化方案此配置用到了jackson2JsonRedisSerializer 的序列化器(忘了要不要引入依赖)代码参考案例如下 Configuration public class RedisConfig {Beanpublic RedisTemplateObject, Object redisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplateObject, Object redisTemplate new RedisTemplate();redisTemplate.setConnectionFactory(connectionFactory);// 使用Jackson2JsonRedisSerialize 替换默认序列化(默认采用的是JDK序列化)Jackson2JsonRedisSerializerObject jackson2JsonRedisSerializer new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);redisTemplate.setKeySerializer(jackson2JsonRedisSerializer);redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);redisTemplate.setHashKeySerializer(jackson2JsonRedisSerializer);redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);return redisTemplate;} } 2.直接使用StringRedisTemplate StringRedisTemplate是Spring Data Redis定义好的一个操作redis的模版继承了redisTemplate默认使用了字符串序列序列化器就是key和value都是用String进行存储,定制RedisTemplate狭义无非是定义哪种存储类型的序列化器上面第一种数一种Json形式的序列化器在本文章中在实现限流功能上没有区别。 我选择这种的理由懒不用配置但是注意传入的key和value都要先转为toString()转为字符串不然会报错 4. 开放lua脚本 lua脚本操作Redis的目的就是为了保证多个Redis操作的原子性如果其中一条Redis操作出错了可以抛出异常给springboot进行Redis回滚。如果不知道怎么使用lua脚本可以去B站黑马Redis关于lua的几节补补。 2.脚本流程的意思大概如下: 首先获取到传进来的 key 以及 限流的 count 和时间 time。通过 get 获取到这个 key 对应的值这个值就是当前时间窗内这个接口可以访问多少次。如果是第一次访问此时拿到的结果为 nil否则拿到的结果应该是一个数字所以接下来就判断如果拿到的结果是一个数字并且这个数字还大于 count那 就说明已经超过流量限制了那么直接返回查询的结果即可。如果拿到的结果为 nil说明是第一次访问此时就给当前 key 自增 1然后设置一个过期时间。最后把自增 1 后的值返回就可以了。 -- redis限流脚本 -- key参数 local key KEYS[1] -- 限流的次数 local limitCount tonumber(ARGV[1]) -- 限流的时间 local limitTime tonumber(ARGV[2]) -- 获取当前时间 local currentCount redis.call(get, key) -- if 获取key的当前数 limitCount 则返回最大值 if currentCount and tonumber(currentCount) limitCount thenreturn tonumber(currentCount) end -- key 自增1 currentCount redis.call(incr,key) -- if key的值 1 设置过期限流过期时间 if tonumber(currentCount) 1 thenredis.call(expire,key,limitTime) end -- 返回key的值 return tonumber(currentCount) 5.注解解析 springboot记得在main方法开启aop注解功能(不会自己查)核心代码如下(看不懂问gpt)代码中的异常为自定义异常可换成自己的异常类抛出或处理异常 Component Aspect Slf4j public class RateLimiterAspect {Resourceprivate StringRedisTemplate stringRedisTemplate;Resourceprivate RedisScriptLong limitScript;Before(annotation(rateLimiter))public void doBefore(JoinPoint point, RateLimiter rateLimiter) {String key rateLimiter.key();int time rateLimiter.time();int count rateLimiter.count();String combineKey getCombineKey(rateLimiter, point);ListString keys Collections.singletonList(combineKey);try {Long number stringRedisTemplate.execute(limitScript, keys, String.valueOf(count), String.valueOf(time));if (numbernull || number.intValue() count) {throw new BusinessException(ErrorCode.PARAMS_ERROR,访问过于频繁请稍候再试);}log.info(限制请求{},当前请求{},缓存key{}, count, number.intValue(), keys.get(0));} catch (ServiceException e) {throw e;} catch (Exception e) {throw new BusinessException(ErrorCode.SYSTEM_ERROR, 系统繁忙请稍候再试);}}/*** 获取ip为key* param rateLimiter* param point* return*/public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) {StringBuffer stringBuffer new StringBuffer(rateLimiter.key());if (rateLimiter.limitType() LimitType.IP) {stringBuffer.append(IpUtils.getIpAddr(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest())).append(-);}MethodSignature signature (MethodSignature) point.getSignature();Method method signature.getMethod();Class? targetClass method.getDeclaringClass();stringBuffer.append(targetClass.getName()).append(-).append(method.getName());return stringBuffer.toString();}} 根据HttpRequest获取用户ip的工具类(看不懂细节问gpt) public class IpUtils {public static String getIpAddr(HttpServletRequest request) {String ipAddress null;try {ipAddress request.getHeader(x-forwarded-for);if (ipAddress null || ipAddress.length() 0 || unknown.equalsIgnoreCase(ipAddress)) {ipAddress request.getHeader(Proxy-Client-IP);}if (ipAddress null || ipAddress.length() 0 || unknown.equalsIgnoreCase(ipAddress)) {ipAddress request.getHeader(WL-Proxy-Client-IP);}if (ipAddress null || ipAddress.length() 0 || unknown.equalsIgnoreCase(ipAddress)) {ipAddress request.getRemoteAddr();if (ipAddress.equals(127.0.0.1)) {// 根据网卡取本机配置的IPtry {ipAddress InetAddress.getLocalHost().getHostAddress();} catch (UnknownHostException e) {e.printStackTrace();}}}// 通过多个代理的情况第一个IP为客户端真实IP,多个IP按照,分割if (ipAddress ! null) {if (ipAddress.contains(,)) {return ipAddress.split(,)[0];} else {return ipAddress;}} else {return ;}} catch (Exception e) {e.printStackTrace();return ;}} } 6.接口测试 如下: 根据用户IP地址60秒只能调用一次接口 GetMapping(/message)RateLimiter(time 60,count 1,limitType LimitType.IP)public BaseResponseString sendMessage(String phone,HttpServletRequest request) {if (StringUtils.isBlank(phone)) {throw new BusinessException(ErrorCode.PARAMS_ERROR);}boolean result userVenueReservationService.sendMessage(phone,request);return ResultUtils.success(result ? 发送成功 : 发送失败);}有错再补~~
http://www.tj-hxxt.cn/news/225008.html

相关文章:

  • 建个站的网站打不开辛集做网站公司
  • 哪些购物网站做的比较简洁有品质wordpress弹窗
  • 湘潭市 网站建设如何做双语网站
  • 网站营销单页怎么设计方案招投标网站开发费用
  • 诚讯通网站网站的建设
  • 西安营销网站建设公司做网站彩票代理多少钱啊
  • 手机网站怎么做域名解析广州英文建站公司
  • 扁平化手机网站模板陕西省平安建设网站
  • 专业的网站开发公司电话上海做网站天锐
  • 装潢公司网站源码php封面设计用什么软件做
  • 网站建设 案例展示网站原型怎么做
  • 网站建设预计资金投入天美传媒传媒官网免费下载
  • 廊坊网站搜索优化百度搜索引擎怎么做
  • 广州网站建设菲利宾手机百度下载安装
  • 长春做高端网站公司营销推广内容
  • 那个网站做图片比较赚钱售后好的品牌策划公司
  • 黑龙江省住房和建设厅网站首页洛阳理工学院教务管理系统
  • 个人无网站怎样做cps广告电子报刊的传播媒体是什么
  • 什么网站好建设wordpress支付宝当面付插件
  • 昆明网站建设哪家好iis 配置 wordpress
  • 怎么才能让百度收录网站wordpress文章推送公众号
  • 花网站开发背景物业管理系统和物业管理软件
  • 沧州哪家做网站好wordpress 支持rar
  • 企业管理咨询公司注册条件河北百度seo点击软件
  • 山东专业企业网站建设做企业网站报价
  • 网站外链接自己可以怎么做wordpress建站不好用
  • 郑州网站维护电商网站开发ppt
  • 折扣网站怎么做wordpress 显示视频
  • 专业集团门户网站建设wordpress数组转字符串
  • 山东专业网站建设苏州网站