>  기사  >  백엔드 개발  >  app接口开发:如何限制app一次发送多次同一个请求

app接口开发:如何限制app一次发送多次同一个请求

WBOY
WBOY원래의
2016-06-06 20:35:361700검색

问题:
app中有积分体系,用户签到时会发送请求到服务器记录用户的签到信息,但是app抽风会并发发送多个同一个请求上来,这样的结果是虽然有验证是否签到,但是多个请求会穿透这个验证(多个请求都还没有写签到信息到数据库)导致数据库中会出现两次同样记录的情况出现。这种问题该如何解决

目前的解决方案:

<code>select ... for update
</code>

用数据库加锁的方式可以解决,但这种就把问题抛给了数据库,如何解决这样的问题?

问题补充
使用缓存(redis)屏蔽同一个请求,但是也不能彻底解决:

<code>//屏蔽同一请求

// 请求数据生成key
$forbidsameRequest = md5(implode('',$reqDatas));

if (Cache::has($forbidsameRequest))
{
    Log::info("the same request", $reqDatas);
    return Util::returnError();
}

Cache::put($forbidsameRequest, true, $this->_forbiddenTime);

省略逻辑处理...

// 处理后释放key
Cache::forget($forbidsameRequest);
</code>

回复内容:

问题:
app中有积分体系,用户签到时会发送请求到服务器记录用户的签到信息,但是app抽风会并发发送多个同一个请求上来,这样的结果是虽然有验证是否签到,但是多个请求会穿透这个验证(多个请求都还没有写签到信息到数据库)导致数据库中会出现两次同样记录的情况出现。这种问题该如何解决

目前的解决方案:

<code>select ... for update
</code>

用数据库加锁的方式可以解决,但这种就把问题抛给了数据库,如何解决这样的问题?

问题补充
使用缓存(redis)屏蔽同一个请求,但是也不能彻底解决:

<code>//屏蔽同一请求

// 请求数据生成key
$forbidsameRequest = md5(implode('',$reqDatas));

if (Cache::has($forbidsameRequest))
{
    Log::info("the same request", $reqDatas);
    return Util::returnError();
}

Cache::put($forbidsameRequest, true, $this->_forbiddenTime);

省略逻辑处理...

// 处理后释放key
Cache::forget($forbidsameRequest);
</code>

这就是典型的防重放攻击场景。
要求请求端带上一个随机字符串state(也可以是特定规则生成的,甚至是从服务器上请求过来的),服务端(用过滤/拦截器之类的实现不会影响业务代码)收到之后缓存一定的时间(长短视业务和硬件),每次请求都检查state值是否在缓存中存在(或者是否符合规则,或者是否由服务器生成),如果存在抛弃或者给出特别的响应,第一个被接受的请求就按照正常处理。
需要注意的是,判断并缓存这是要一个原子操作。

好奇,为什么会重发两次,试试在APP上做个简单验证?

可以先将签到信息记录到 Redis 缓存中, 验证的逻辑也直接使用 Redis 缓存中的数据, 再异步把签到数据写入数据库

你数据表中记录签到的字段是什么?如果是类似一个用户 id (uid) 和一个类似时间戳 timestamp 的东西,可以把这两个字段设为 unique key

你这种情况, 可以使用 Nginx 的漏桶 limit_req_zone 做限速设置 limit_req 来控制 单一 IP 的并发量. 比如你可以这样设置: 针对每个 IP 每秒钟只处理一个请求, 最大并发量为5个, 那么 一秒内发送并发的5个请求, 会有1个被处理, 其他4个进入延迟处理.

或者 所有的请求统一放入一个队列, 依次处理

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.