pyaesoneaung / atomic-locks-middleware
一个设计用来确保一次只处理一个请求的包。
v1.2.0
2024-03-12 15:49 UTC
Requires
- php: ^8.1
- illuminate/contracts: ^9.0|^10.0|^11.0
- spatie/laravel-package-tools: ^1.0
Requires (Dev)
- laravel/pint: ^1.0
- nunomaduro/collision: ^6.0
- nunomaduro/larastan: ^2.0.1
- orchestra/testbench: ^7.0|^8.0|^9.0
- pestphp/pest: ^1.21
- pestphp/pest-plugin-laravel: ^1.1
- phpstan/extension-installer: ^1.1
- phpstan/phpstan-deprecation-rules: ^1.0
- phpstan/phpstan-phpunit: ^1.0
- phpunit/phpunit: ^9.5
README
一个设计用来确保一次只处理一个请求的包。
安装
composer require pyaesoneaung/atomic-locks-middleware
使用
默认情况下,atomic-locks-middleware 在原子锁中使用 $request->user()?->id ?: $request->ip()
。
Route::post('/order', function () { // ... })->middleware('atomic-locks-middleware');
如果您更喜欢基于IP的锁定,可以使用 atomic-locks-middleware:ip
。
Route::post('/order', function () { // ... })->middleware('atomic-locks-middleware:ip');
但是,您有灵活性来定义 atomic-locks-middleware:{anything}
以根据您的喜好自定义锁定机制。
Route::post('/order', function () { // ... })->middleware('atomic-locks-middleware:{anything}');
您还可以向中间件传递额外的参数以进行更多自定义。可用的参数包括
{anything} (string)
: 您的自定义锁定机制。{lockDuration} (int)
: 锁定保留的持续时间。{canBlock} (bool)
: 请求是否可以等待锁。{blockDuration} (int)
: 如果允许等待,等待锁的最大持续时间。
如果没有提供额外的参数,将使用配置文件中的默认值。
Route::post('/order', function () { // ... })->middleware('atomic-locks-middleware:{anything}'); Route::post('/purchase', function () { // ... })->middleware('atomic-locks-middleware:{anything},60,true,60'); Route::post('/payment/process', function () { // ... })->middleware('atomic-locks-middleware:{anything},60,false');
它是如何工作的?
// AtomicLocksMiddleware.php public function handle(Request $request, Closure $next, string $option = null, int $lockDuration = null, string $canBlock = null, int $blockDuration = null): Response { if (! empty($canBlock)) { $canBlock = filter_var($canBlock, FILTER_VALIDATE_BOOLEAN); } $name = match ($option) { null => $request->user()?->id ?: $request->ip(), 'ip' => $request->ip(), default => $option }; $name = "{$request->path()}_{$name}"; $lock = Cache::lock( config('atomic-locks-middleware.lock_prefix') . $name, $lockDuration ?: config('atomic-locks-middleware.default_lock_duration') ); if (! $lock->get()) { if (! ($canBlock ?? config('atomic-locks-middleware.can_block'))) { return response()->json([ 'message' => config('atomic-locks-middleware.message'), ], 429); } try { $lock->block($blockDuration ?: config('atomic-locks-middleware.default_block_duration')); } catch (LockTimeoutException) { $lock->release(); return response()->json([ 'message' => config('atomic-locks-middleware.block_timeout_error_message'), ], 500); } catch (Throwable $th) { $lock->release(); return response()->json([ 'message' => $th->getMessage(), ], 500); } } app()->instance(config('atomic-locks-middleware.instance'), $lock); return $next($request); } /** * Handle tasks after the response has been sent to the browser. */ public function terminate(Request $request, Response $response): void { $instanceName = config('atomic-locks-middleware.instance'); if (app()->bound($instanceName)) { app($instanceName)->release(); } }
Atomic Locks Middleware 在后台使用 Laravel Atomic Locks。它在中件执行开始时初始化锁,并在将响应分派到浏览器后释放锁。
发布配置
发布配置以进行自定义
php artisan vendor:publish --provider="PyaeSoneAung\AtomicLocksMiddleware\AtomicLocksMiddlewareServiceProvider"
return [ 'middleware_name' => 'atomic-locks-middleware', 'middleware_class' => PyaeSoneAung\AtomicLocksMiddleware\AtomicLocksMiddleware::class, 'instance' => 'AtomicLocksMiddleware', 'lock_prefix' => 'atomic_locks_middleware_', 'default_lock_duration' => 60, 'can_block' => false, 'default_block_duration' => 60, // It's generally recommended to set the block duration to be longer than the lock duration. 'block_timeout_error_message' => 'Timeout: Unable to acquire lock within the specified time.', 'message' => 'Too Many Attempts', ];
测试
composer test