PHP接口防重推荐实现
防重机制的必要性
在API开发中,防止重复请求是保证数据一致性和系统稳定性的关键。重复请求可能导致重复扣款、重复提交订单等问题。
基于Token的防重方案
客户端在请求前先获取一个唯一Token(如UUID),服务端将该Token存入Redis并设置过期时间。
客户端携带Token发起请求,服务端校验Token是否存在:存在则处理请求并删除Token;不存在则拒绝请求。

// 生成Token并存储
$token = uniqid('api_', true);
$redis->setex("api_token:$token", 300, 1); // 5分钟有效期
// 验证Token
if (!$redis->exists("api_token:".$_POST['token'])) {
die(json_encode(['code' => 400, 'msg' => '重复请求']));
}
$redis->del("api_token:".$_POST['token']);
基于时间戳+签名的防重
请求参数包含时间戳(timestamp)和签名(sign)。服务端校验时间戳是否在有效期内(如5分钟内),并重新计算签名是否匹配。

$secretKey = 'your_secret';
$timestamp = $_POST['timestamp'];
$sign = $_POST['sign'];
// 时间有效性校验
if (time() - $timestamp > 300) {
die('请求已过期');
}
// 签名校验
$expectedSign = md5($timestamp . $secretKey);
if ($sign !== $expectedSign) {
die('签名无效');
}
基于幂等性设计的防重
对写操作接口设计幂等性,如订单创建接口使用唯一业务ID(如订单号)。服务端先查询该ID是否存在,存在则直接返回结果。
$orderId = $_POST['order_id'];
if ($db->query("SELECT id FROM orders WHERE order_id = '$orderId'")) {
die('订单已存在');
}
// 处理订单创建逻辑
基于限流的防重
使用Redis计数器限制单位时间内同一用户的请求次数。例如每分钟允许5次请求:
$userId = $_SESSION['user_id'];
$key = "api_limit:$userId:" . date('YmdHi');
$count = $redis->incr($key);
$redis->expire($key, 60);
if ($count > 5) {
die('请求过于频繁');
}
混合策略建议
- 关键业务(如支付)建议组合Token+幂等性设计
- 高频接口采用限流+时间戳签名
- Redis存储需考虑集群部署时的数据一致性






