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

电商个人网站建设非企户百度推广

电商个人网站建设,非企户百度推广,网页设计制作工资,做个人网站怎么做一,概述 日常开发中会有一个常见的需求,需要限制接口在单位时间内的访问次数,比如说某个免费的接口限制单个IP一分钟内只能访问5次。该怎么实现呢,通常大家都会想到用redis,确实通过redis可以实现这个功能&#xff0c…

一,概述

日常开发中会有一个常见的需求,需要限制接口在单位时间内的访问次数,比如说某个免费的接口限制单个IP一分钟内只能访问5次。该怎么实现呢,通常大家都会想到用redis,确实通过redis可以实现这个功能,下面实现一下。

二,常见错误

固定时间窗口

有人设计了一个在每分钟内只允许访问1000次的限流方案,如下图01:00s-02:00s之间只允许访问1000次。这种设计的问题在于,请求可能在01:59s-02:00s之间被请求1000次,02:00s-02:01s之间被请求了1000次,这种情况下01:59s-02:01s间隔0.02s之间被请求2000次,很显然这种设计是错误的。

三, 实现

1,基于滑动时间窗口

在指定的时间窗口内次数是累积的,超过阈值,都会限制。

2,流程如下

3,代码实现

前提:pom文件引入redis,Spring AOP等

(1)添加注解RequestLimit
package com.xxx.demo.aspect;import java.lang.annotation.*;/*** 接口访问频率注解,默认一分钟只能访问10次*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestLimit {// 限制时间 单位:秒(默认值:一分钟)long period() default 60;// 允许请求的次数(默认值:10次)long count() default 10;
}
(2)添加切面实现注解的限制访问逻辑
package com.xxx.demo.aspect;import com.xgd.demo.commons.ErrorCode;
import com.xgd.demo.handler.BusinessException;
import com.xgd.demo.util.IpUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.concurrent.TimeUnit;/*** @date 2024/11/8 上午8:43*/
@Aspect
@Component
@Log4j2
public class RequestLimitAspect {@AutowiredRedisTemplate redisTemplate;@Pointcut("@annotation(requestLimit)")public void controllerAspect(RequestLimit requestLimit) {}@Around("controllerAspect(requestLimit)")public Object doAround(ProceedingJoinPoint joinPoint, RequestLimit requestLimit) throws Throwable {// 从注解中获取限制次数和窗口时间long period = requestLimit.period();long limitCount = requestLimit.count();// 请求ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();assert attributes != null;HttpServletRequest request = attributes.getRequest();String ip = IpUtil.getIpFromRequest(request);String uri = request.getRequestURI();//设置客户端访问的keyString key = "req_limit_".concat(uri).concat(ip);ZSetOperations zSetOperations = redisTemplate.opsForZSet();// 添加当前时间戳,分数为当前时间戳long currentMs = System.currentTimeMillis();zSetOperations.add(key, currentMs, currentMs);// 设置窗口时间作为过期时间redisTemplate.expire(key, period, TimeUnit.SECONDS);// 移除掉不在窗口里的数据zSetOperations.removeRangeByScore(key, 0, currentMs - period * 1000);// 查询窗口内已经访问过的次数Long count = zSetOperations.zCard(key);if (count > limitCount) {log.error("接口拦截:{} 请求超过限制频率【{}次/{}s】,IP为{}", uri, limitCount, period, ip);throw new BusinessException(ErrorCode.REQUEST_LIMITED.getCode(), ErrorCode.REQUEST_LIMITED.getMessage());}// 继续执行请求return  joinPoint.proceed();}
}

上面里面请求被拦截,是抛出了一个自定义的业务异常,大家可以根据自己的情况自己定义。

(3)同时附上上面中引用到自定义工具类
package com.xxx.demo.util;import jakarta.servlet.http.HttpServletRequest;
import java.util.Objects;/*** @date 2024/11/8 上午9:06*/
public class IpUtil {private static final String X_FORWARDED_FOR_HEADER = "X-Forwarded-For";private static final String X_REAL_IP_HEADER = "X-Real-IP";/*** 从请求中获取IP** @return IP;当获取不到时,返回null*/public static String getIpFromRequest(HttpServletRequest request ) {return getRealIp(request);}/*** 获取请求的真实IP,优先级从高到低为:<br/>* 1.从请求头X-Forwarded-For中获取ip,并且只获取第一个ip(从左到右) <br/>* 2.从请求头X-Real-IP中获取ip <br/>* 3.使用{@link HttpServletRequest#getRemoteAddr()}方法获取ip** @param request 请求对象,必须不能为null* @return ip*/private static String getRealIp(HttpServletRequest request) {Objects.requireNonNull(request, "request must be not null");String ip = request.getHeader(X_FORWARDED_FOR_HEADER);if (ip != null && !ip.isBlank()) {int delimiterIndex = ip.indexOf(',');if (delimiterIndex != -1) {// 如果存在多个ip,则取第一个ipip = ip.substring(0, delimiterIndex);}return ip;}ip = request.getHeader(X_REAL_IP_HEADER);if (ip != null && !ip.isBlank()) {return ip;} else {return request.getRemoteAddr();}}
}
(4)使用注解

这里限制为10秒内只允许访问3次,超过就抛出异常

(5)访问测试

前3次访问,接口正常访问

后面的访问,返回自定义异常的结果

如果对你有帮助,记得点赞关注哟!

http://www.yidumall.com/news/49679.html

相关文章:

  • 上海高端网站建设百度指数数据分析
  • 什么网站做教育的比较多互联网营销师培训课程免费
  • 专业网上商城开发整站优化和关键词优化的区别
  • wordpress title description南平seo
  • 广州网站建设 骏域网站建设专家永久免费二级域名申请
  • 优设计网站长沙seo全网营销
  • flash网站源码带asp后台怎么开一个网站平台
  • 学校如何报销网站开发费用同城引流用什么软件
  • 公司怎么做网页网站seo在线论坛
  • 淘宝店铺可以做网站优化么爱站网站排行榜
  • 衣邦人上门定制靠谱吗百度seo优化多少钱
  • 网络购物平台哪个最好咸宁网站seo
  • 常用来做网站的首页想做电商应该怎么入门
  • 关于门户网站建设经费的报告百度站长工具
  • 品牌和网站建设黑帽seo排名优化
  • 深圳做网站哪家便宜b站免费建网站
  • wordpress网站微信支付百度收录排名
  • ps 制作网站搜索引擎的网址有哪些
  • 中国建设银行的网站河南seo关键词排名优化
  • wordpress 局域网访问不了搜索引擎排名优化技术
  • wordpress 网站地图网站托管维护
  • 网站点击滚动图片代码青岛seo网站排名优化
  • 商城网站建设定制网站建设seo排名优化的方法
  • 外贸做哪个网站好软文范例大全200字
  • 四川住房和城乡建设网站优化seo搜索
  • 网站建设经验分享百度关键词排名十大排名
  • 外贸网站推广公司最大百度关键词价格
  • 建设银行网站 一带一路上海网站建设优化
  • wordpress搜索词结果按文章标题seo优化技巧
  • 做外贸怎样上外国网站西安百度网站快速优化