在前两篇文章的介绍下,我们完成了防止超卖商品和抢购接口的限流,已经能够防止大流量把我们的服务器直接搞炸,这篇文章中,我们要开始关心一些细节问题。对于稍微懂点电脑的,点击F12打开浏览器的控制台,就能在点击抢购按钮后,获取我们抢购接口的链接(手机APP等其他客户端可以抓包来拿到)。一旦拿到了抢购的链接,只要稍微写点爬虫代码,模拟一个抢购请求,就可以不通过点击下单按钮,直接在代码中请求我们的接口,完成下单。他们只需要在抢购时刻的0毫秒,开始不间断发起大量请求,绝对比大家在APP上点抢购按钮要快,毕竟人的速度有限,更别说APP说不定还要经过几层前端验证才会真正发出请求。本篇我们从两个方面对所出现的问题来进行相关限制:抢购接口隐藏和单用户限制频率。
抢购接口隐藏
如果在秒杀活动活动开始前不知道具体的接口,那是不是就不能发起请求了?所以我们可以将抢购接口进行隐藏,抢购接口隐藏(接口加盐)的具体做法:
- 每次点击秒杀按钮,先从服务器获取一个秒杀验证值(接口内判断是否到秒杀时间);
- Redis以缓存用户ID和商品ID为Key,秒杀地址为Value缓存验证值;
- 用户请求秒杀商品的时候,要带上秒杀验证值进行校验。
其实这种方式可以防住的是直接请求接口的人,但是只要把脚本写复杂一点,先去请求一个验证值,再立刻请求抢购,也是能够抢购成功的。不过请求验证值接口,也需要在抢购时间开始后,才能请求接口拿到验证值,然后才能申请抢购接口。理论上来说在访问接口的时间上受到了限制,并且我们还能通过在验证值接口增加更复杂的逻辑,让获取验证值的接口并不快速返回验证值,进一步拉平普通用户和恶意请求的下单时刻。所以接口加盐还是有用的!下面我们就实现一种简单的加盐接口代码,抛砖引玉。
接口加盐实现
代码还是使用之前的项目,我们在其上面增加两个接口:获取验证值接口和携带验证值下单接口。之前我们只有两个表,一个stock表放库存商品,一个stockOrder订单表,放订购成功的记录。但是这次涉及到了用户,所以我们新增用户表,并且添加一个用户王二。并且在订单表中,不仅要记录商品id,同时要写入用户id。
创建SQL语句
-- ----------------------------
-- Table structure for stock
-- ----------------------------
DROP TABLE IF EXISTS `stock`;
CREATE TABLE `stock` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL DEFAULT '' COMMENT '名称',
`count` int(11) NOT NULL COMMENT '库存',
`sale` int(11) NOT NULL COMMENT '已售',
`version` int(11) NOT NULL COMMENT '乐观锁,版本号',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of stock
-- ----------------------------
INSERT INTO `stock` VALUES ('1', 'iphone', '50', '0', '0');
INSERT INTO `stock` VALUES ('2', 'mac', '10', '0', '0');
-- ----------------------------
-- Table structure for stock_order
-- ----------------------------
DROP TABLE IF EXISTS `stock_order`;
CREATE TABLE `stock_order` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`sid` int(11) NOT NULL COMMENT '库存ID',
`name` varchar(30)