电商项目-秒杀系统(五) 秒杀下单接口限流

news/2025/3/11 4:03:39/

一、 秒杀下单接口隐藏

在实际开发中,我们一般都会将后端的访问接口来进行隐藏,从而防止一些恶意用户,去猜测我们的后端地址,来进行恶意的访问。

当前虽然可以确保用户只有在登录的情况下才可以进行秒杀下单,但是无法防止有一些恶意的用户在登录了之后,猜测秒杀下单的接口地址进行恶意刷单。所以需要对秒杀接口地址进行隐藏。

在用户每一次点击抢购的时候,都首先去生成一个随机数并存入redis,接着用户携带着这个随机数去访问秒杀下单,下单接口首先会从redis中获取该随机数进行匹配,如果匹配成功,则进行后续下单操作,如果匹配不成功,则认定为非法访问。

1) 将随机数工具类放入common工程中

public class RandomUtil {public static String getRandomString() {int length = 15;String base = "abcdefghijklmnopqrstuvwxyz0123456789";Random random = new Random();StringBuffer sb = new StringBuffer();for (int i = 0; i < length; i++) {int number = random.nextInt(base.length());sb.append(base.charAt(number));}return sb.toString();}public static void main(String[] args) {String randomString = RandomUtil.getRandomString();System.out.println(randomString);}
}

2) 秒杀渲染服务定义随机数接口

/**
* 接口加密
* 生成随机数存入redis,10秒有效期
*/
@GetMapping("/getToken")
@ResponseBody
public String getToken(){String randomString = RandomUtil.getRandomString();String cookieValue = this.readCookie();redisTemplate.boundValueOps("randomcode_"+cookieValue).set(randomString,10, TimeUnit.SECONDS);return randomString;
}//读取cookie
private String readCookie(){HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();String cookieValue = CookieUtil.readCookie(request, "uid").get("uid");return cookieValue;
}

3) js修改
修改js下单方法

//秒杀下单
add:function(id){app.msg ='正在下单';//获取随机数axios.get("/api/wseckillorder/getToken").then(function (response) {var random=response.data;axios.get("/api/wseckillorder/add?time="+moment(app.dateMenus[0]).format("YYYYMMDDHH")+"&id="+id+"&random="+random).then(function (response) {if (response.data.flag){app.msg='抢单成功,即将进入支付!';}else{app.msg='抢单失败';}})})}

4) 秒杀渲染服务更改
修改秒杀渲染服务下单接口

/*** 秒杀下单* @param time 当前时间段* @param id 秒杀商品id* @return*/
@RequestMapping("/add")
@ResponseBody
public Result add(String time,Long id,String random){//校验密文有效String randomcode = (String) redisTemplate.boundValueOps("randomcode").get();if (StringUtils.isEmpty(randomcode) || !random.equals(randomcode)){return new Result(false, StatusCode.ERROR,"无效访问");}Result result = secKillOrderFeign.add(time, id);return result;
}

二、 秒杀下单接口限流

因为秒杀的特殊业务场景,生产场景下,还有可能要对秒杀下单接口进行访问流量控制,防止过多的请求进入到后端服务器。对于限流的实现方式,我们之前已经接触过通过nginx限流网关限流。但是他们都是对一个大的服务进行访问限流,如果现在只是要对某一个服务中的接口方法进行限流呢?这里推荐使用google提供的guava工具包中的RateLimiter进行实现,其内部是基于令牌桶算法进行限流计算

1)添加依赖

<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>28.0-jre</version>
</dependency>

2)自定义限流注解

@Inherited
@Documented
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AccessLimit {}

3)自定义切面类

@Component
@Scope
@Aspect
public class AccessLimitAop {@Autowiredprivate HttpServletResponse httpServletResponse;private RateLimiter rateLimiter = RateLimiter.create(20.0);@Pointcut("@annotation(com.shangcheng.webSecKill.aspect.AccessLimit)")public void limit(){}@Around("limit()")public Object around(ProceedingJoinPoint proceedingJoinPoint){boolean flag = rateLimiter.tryAcquire();Object obj = null;try{if (flag){obj=proceedingJoinPoint.proceed();}else{String errorMessage = JSON.toJSONString(new Result(false,StatusCode.ERROR,"fail"));outMessage(httpServletResponse,errorMessage);}}catch (Throwable throwable) {throwable.printStackTrace();}return obj;}private void outMessage(HttpServletResponse response, String errorMessage) {ServletOutputStream outputStream = null;try {response.setContentType("application/json;charset=UTF-8");outputStream = response.getOutputStream();outputStream.write(errorMessage.getBytes("UTF-8"));} catch (IOException e) {e.printStackTrace();}finally {try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}}
}

4)使用自定义限流注解


http://www.ppmy.cn/news/1578252.html

相关文章

http status是什么?常见的http状态码指的是什么意思?

HTTP 状态码 HTTP 状态码&#xff08;HTTP Status Code&#xff09;是服务器在响应客户端请求时返回的一个三位数字代码&#xff0c;用于表示请求的处理结果。HTTP 状态码是 HTTP 协议的一部分&#xff0c;帮助客户端&#xff08;如浏览器或应用程序&#xff09;了解请求是否成…

基于遗传算法的IEEE33节点配电网重构程序

一、配电网重构原理 配电网重构&#xff08;Distribution Network Reconfiguration, DNR&#xff09;是一项优化操作&#xff0c;旨在通过改变配电网中的开关状态&#xff0c;优化电力系统的运行状态&#xff0c;以达到降低网损、均衡负载、改善电压质量等目标。配电网重构的核…

Java集合框架全解析:从数据结构到高并发简单解析

一、集合框架全景图&#xff08;含Java 17新特性&#xff09; 1. 集合框架层级关系 #mermaid-svg-LlczMwnXbqARTW22 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-LlczMwnXbqARTW22 .error-icon{fill:#552222;}#m…

Java 大视界 -- Java 大数据在智能家居能源管理与节能优化中的应用(120)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

DeepSeek:中国大模型领域的“效率革命者”与开源先锋

一、DeepSeek的技术定位与核心突破 DeepSeek(深度求索)是中国量化私募巨头幻方量化旗下的人工智能公司,专注于通用人工智能(AGI)的研发与应用。作为大模型领域的“黑马”,其核心创新在于通过算法优化而非单纯堆砌算力,实现了性能与成本的平衡突破。其最新发布的推理模型…

DeepSeek开源Day4:DualPipeEPLB技术详解

2 月 24 日&#xff0c;DeepSeek 启动 “开源周”&#xff0c;第四个开源的代码库为 DualPipe 与 EPLB&#xff08;一下发布了两个&#xff09;。DualPipe 与 EPLB 依然使用了大量与 Hopper 架构绑定的技术。 DualPipe 是由 DeepSeek-AI 团队开发的一种双向流水线并行通信算法&…

Calico-BGP FullMesh模式与RR模式 Day04

1. BGP协议简单介绍 BGP是什么&#xff1f;BGP是如何工作的&#xff1f; - 华为 Configure BGP peering | Calico Documentation 1.1 什么是BGP 边界网关协议&#xff08;BGP&#xff09;是一种用于在网络中的路由器之间交换路由信息的标准协议。每台运行 BGP 的路由器都有一…

基于flask的一个数据展示网页

前言 开发语言&#xff1a;python3.11.6、javascript、html5‘、css3 开发框架&#xff1a;flask、plotly.js 开发系统&#xff1a;windows10 22H2 开发编辑器&#xff1a;vscode 作用&#xff1a;展示水产养殖水体氨氮和亚硝酸盐时间序列数据&#xff0c;使用LWLR、ESE、…