Laravel接口幂中间件
初始化
1. 新建中间件 app/Http/Middleware/UniqueLockMiddleware.php
<?php
declare(strict_types=1);
namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
class UniqueLockMiddleware
{
// 接口幂
public function handle(Request $request, \Closure $next)
{
$lock = $request->route()->getAction('lock');
if($lock === null){ // 未定义lock的属性 正常处理
return $next($request);
}
$unique_value = $request[$lock['field']]; // 请求包的唯一标识 一般是id或者订单号
if(empty($unique_value)){ // 唯一标识为空
return $next($request);
}
$lock_key = sprintf("lock_%s_%s",$lock['prefix'],$unique_value);
return Cache::lock($lock_key,10)->get(fn() => $next($request)); // 10秒超时
}
}
注册全局路由中间件 app/Http/Kernel.php
'web' => [
....,
\App\Http\Middleware\UniqueLockMiddleware::class
]
使用例子
routes/web.php
...
Route::get('/order/{id}', [
'uses' => \App\Http\Controllers\HelloController::class.'@test',
'lock' => [
'prefix' => 'order', // 路由唯一标识 不可重复
'field' => 'id' // 请求包的唯一字段 支持路由参数和请求包的参数
]
]);
原理
原子锁
注意:
注意:要想使用该特性,你的应用必须使用 memcached,dynamodb 或 redis 缓存驱动作为你应用的默认缓存驱动。此外,所有服务器必须与同一中央缓存服务器进行通信。
ps
是否可生产? 我生产环境就是这样的,不可用写他干嘛。
锁是否靠谱? 靠谱。 加了中间件后, 我用 wrk
和 HTTP客户端 - 并发请求 测试,都锁住了。
(我cache
是 redis
)
本作品采用《CC 协议》,转载必须注明作者和本文链接
思路不错,虽然存在一定局限性。不过感觉 key 前缀可以用当前路径代替也不错。
demo可以搞,生产不可用
如果是以id去锁的情况请求完成后应该把锁释放掉 避免影响下一次请求
demo