公众号上线啦!
搜一搜【国服冰】
使命:尽自己所能给自学后端开发的小伙伴提供一个少有弯路的平台
回复:国服冰,即可领取我为大家准备的资料,里面包含整体的Java学习路线,电子书,以及史上最全的面试题!
为什么要链接隐藏,如何隐藏
为了避免F12
或着抓包获取到秒杀链接然后通过不正当手段自动化秒杀,下面我们将接口路径进行隐藏,只有当点击秒杀按钮时才能成功验证。用户在下单前,先发出一个生成Md5
hash
值的请求,根据抢购商品id
和用户Id
用Md5
加密算法和随机盐生成一个hash
值存到redis
中,在redis
中设置过期时间,等用户真正下单时发起的下单请求(秒杀请求)携带着Md5
的hash
值和redis
中已经存在的hash
值作比较是否相等,就能判断此请求是根据脚本发起的请求(没有点击抢购秒杀按钮)还是用户在app
下的单了,避免一些用户的脚本抢购。该业务流程可以应用到任意系统。
当用户点击秒杀按钮时,此时去异步获取秒杀path
:
function getMiaoshaPath() {
var good_id = $("#good_id").val();
$.ajax({
url: "/getmiaoshapath",
type: "GET",
data:{
good_id : good_id
},
success:function (data) {
if(data.code == 0){
miaosha(data.data);
}else{
alert(data.msg)
}
},
error:function () {
alert("服务端请求错误")
}
})
}
@RequestMapping("/getmiaoshapath")
@ResponseBody
public Result<String> getMiaoshaPath(@UserParameter User user,@RequestParam("good_id") int good_id){
if(user == null){
return Result.error(CodeMsg.SESSION_ERROR);
}
String pathUUID = Md5Utils.md5(UUIDUtil.uuid()+"miaoshadizhi");
redisService.set(MiaoShaKey.miaoShaPathKey,user.getId()+":"+good_id,pathUUID);
return Result.success(pathUUID);
}
获取到服务端生成的path
之后传递给秒杀接口进行校验,相等则通过
@RequestMapping("/miaosha_static/{path}")
@ResponseBody
public Result<Integer> miaoSha_static(@RequestParam("good_id") int good_id,
@UserParameter User user,
@PathVariable("path") String path){
//验证path是否正确
boolean isPathCorrect = miaoShaService.checkPath(user, good_id, path);
if(!isPathCorrect){
return Result.error(CodeMsg.SERVER_ERROR);
}
System.out.println("good_id"+good_id+"---"+"user"+":"+user);
//库存标记,如果库存小于零则直接结束,不操作redis
if(isOver.get(good_id)){
return Result.error(CodeMsg.OUT_OF_STOCK);
}
//判断是否还有库存
//预减库存
Long decr = redisService.decr(GoodListKey.miaoshaGoodCountKey, good_id + "");
if(decr < 0){
isOver.put(good_id,true);
return Result.error(CodeMsg.OUT_OF_STOCK);
}
//判断该用户是第一次秒杀,不可重复秒杀
//查找redis缓存,绕开数据库
Miaosha_order miaosha_order = redisService.get(MiaoSha_OrderKey.orderKey,user.getId()+":"+good_id,Miaosha_order.class);
if(miaosha_order != null){
return Result.error(CodeMsg.NO_REPEAT_MIAOSHA);
}
MiaoshaMsg msg = new MiaoshaMsg();
msg.setUser(user);
msg.setGood_id(good_id);
//秒杀入队
provider.miaoshaProvider(msg);
return Result.success(0); //0代表排队中
}
public boolean checkPath(User user,long good_id,String path){
String s = redisService.get(MiaoShaKey.miaoShaPathKey, user.getId() + ":" + good_id, String.class);
return path.equals(s);
}