bvtterfly/replay

此包已被废弃,不再维护。未建议替代包。

Laravel 中间件用于幂等性


README

🚨 该包已被废弃 🚨

我不再使用 Laravel,无法证明维护此包所需的时间。因此,我选择放弃它。请随意fork我的代码并维护自己的副本。

🔄 Replay - 幂等性中间件

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

此包可以轻松使您的端点具有幂等性。

查看有关幂等性的这篇 Stripe 博客文章

实现灵感来源于 Stripe API

💡 特点

  • 通过添加中间件,轻松为您的 API 添加对幂等性请求的支持。
  • 仅适用于 POST 请求。其他端点将被忽略。
  • 仅记录和回放成功的(2xx)和服务器端错误(5xx)响应,而无需再次触摸您的控制器。
  • 可以安全地重试,它不会记录带有客户端错误(4xx)的响应。
  • 为了防止意外误用缓存的响应,请求的签名将得到验证,以确保使用相同的幂等性键和请求组合返回缓存的响应。
  • 使用 Laravel 的原子锁来提供并发保护,以防止竞争条件。

安装

您可以通过 composer 安装此包

composer require bvtterfly/replay

您可以使用以下命令发布配置文件

php artisan vendor:publish --tag="replay-config"

这是已发布配置文件的内容

use Bvtterfly\Replay\StripePolicy;

return [

    /*
    |--------------------------------------------------------------------------
    | Cache Store
    |--------------------------------------------------------------------------
    |
    | This option controls the cache store that gets used while Replay will store the
    | information required for it to function.
    | By default, Replay will use the default cache store.
    |
    | Please see config/cache.php for the list of all available Cache Stores.
    |
     */

    'use' => env('REPLAY_CACHE_STORE', config('cache.default')),

    /*
    |--------------------------------------------------------------------------
    | Replay Master Switch
    |--------------------------------------------------------------------------
    |
    | Replay is enabled by default,
    | Use this setting to enable/disable the Replay.
    |
    */

    'enabled' => env('REPLAY_ENABLED', true),

    /*
    |--------------------------------------------------------------------------
    | Expiration Seconds
    |--------------------------------------------------------------------------
    |
    | This value controls the number of seconds until an idempotency response
    | is considered expired.
    |
    | The default is set to 1 day.
    |
    */

    'expiration' => 60 * 60 * 24,

    /*
    |--------------------------------------------------------------------------
    | Request Header Name
    |--------------------------------------------------------------------------
    |
    | Replay will check this header name to determine
    | if a request is an Idempotency request.
    |
    */

    'header_name' => 'Idempotency-Key',

    /*
    |--------------------------------------------------------------------------
    | Response Header Name
    |--------------------------------------------------------------------------
    |
    | Replay will add this header to previously executed responses
    | that's being replayed from the server.
    |
    | Use null or empty, if you don't need to identify these responses.
    |
    */
    'replied_header_name' => 'Idempotent-Replayed',
    
    /*
    |--------------------------------------------------------------------------
    | Policy
    |--------------------------------------------------------------------------
    |
    | The policy determines whether a request is idempotent and whether the response should
    |  be recorded.
    |
    */

    'policy' => StripePolicy::class,

];

注意:Replay 需要支持 缓存标签 & 原子锁 功能的缓存驱动程序。请参阅 Laravel 文档,以查看您的驱动程序是否支持这些功能。

可选地,您可以使用以下命令发布翻译

php artisan vendor:publish --tag="replay-translations"

✨ 服务器使用

Bvtterfly\Replay\Replay-中间件必须在内核中注册

//app/Http/Kernel.php

protected $routeMiddleware = [
  ...
  'replay' => \Bvtterfly\Replay\Replay,
];

接下来,要使端点具有幂等性,请将 replay 中间件应用于它

Route::post('/payments', function () {
    //
})->middleware('replay');

默认情况下,Replay 将幂等性键作为缓存键存储在缓存存储中,因此所有带有 replay 中间件的路由都使用与幂等性键相同的缓存键。在大多数情况下,这样存储是可行的,但在某些场景中,我们只需要将它们分开。在这些场景中,我们可以使用中间件参数添加缓存键的前缀

Route::post('/payments', function () {
//
})->middleware('replay:payments');

自定义策略

Replay 使用策略来确定请求是否幂等,以及是否应该记录响应。默认情况下,Replay 包含并使用 StripePolicy 策略。要创建自定义策略,您首先需要实现 \Bvtterfly\Replay\Contracts\Policy 接口

use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

interface Policy
{
    public function isIdempotentRequest(Request $request): bool;

    public function isRecordableResponse(Response $response): bool;
}

如果您想查看示例实现,请查看 StripePolicy 类。

要使用此策略,我们可以更改配置文件中的 policy

✨ 客户端使用

要执行幂等性请求,客户端必须向请求提供一个额外的 Idempotency-Key : <key> 标题,并使用一个唯一的键。

建议使用

  • 为创建幂等性唯一键使用 "V4 UUIDs"(例如,07cd2d27-e0dc-466f-8193-28453e9c3023)。
  • 从附加的用户对象中派生键,如购物车的 ID。这提供了一种相对简单的方式来防止重复提交。

一旦 Replay 检测到键,它将在缓存存储中查找它。如果找到,它将提供相同的响应,而无需再次调用控制器操作。

为了识别从服务器重新播放的先前执行响应,请查找头部 Idempotent-Replayed: true

如果重放找不到密钥,它会尝试获取缓存锁并缓存成功或服务器错误响应。然而,如果它无法获取锁,则另一个具有相同键的请求已在进行中,那么它将以HTTP冲突响应状态码响应。

重置缓存

如果您需要手动为此软件包重置缓存,可以使用以下Artisan命令

php artisan replay:cache-reset

🧪 测试

composer test

变更日志

请参阅变更日志获取有关最近更改的更多信息。

安全漏洞

请查阅我们的安全策略了解如何报告安全漏洞。

致谢

许可证

MIT许可证(MIT)。有关更多信息,请参阅许可证文件