vladkovrigin / laravel-responsecache
通过缓存整个响应来加速Laravel应用
Requires
- php: ^8.1
- illuminate/cache: ^10.0|^11.0
- illuminate/console: ^10.0|^11.0
- illuminate/container: ^10.0|^11.0
- illuminate/http: ^10.0|^11.0
- illuminate/support: ^10.0|^11.0
- jenssegers/agent: ^2.6
- nesbot/carbon: ^2.63|^3.0
- spatie/laravel-package-tools: ^1.9
Requires (Dev)
- laravel/framework: ^10.0|^11.0
- mockery/mockery: ^1.4
- orchestra/testbench: ^8.0|^9.0
- pestphp/pest: ^2.22
README
通过缓存整个响应来加速应用
这个Laravel包可以缓存整个响应。默认情况下,它会缓存所有返回基于文本内容(如html和json)的成功get请求一周。这可能会显著加快响应速度。
所以第一次请求进来时,包会保存响应然后再发送给用户。当同样的请求再次进来时,我们不需要通过整个应用程序,只需要用保存的响应来响应。
你是视觉学习者吗?那么请观看这个视频,它涵盖了如何使用laravel-responsecache以及它是如何在底层工作的。
支持我们
我们投入了大量资源来创建最好的开源包。您可以通过购买我们的付费产品来支持我们。
我们非常感谢您从家乡寄给我们明信片,说明您正在使用我们的哪些包。您可以在我们的联系页面上找到我们的地址。我们将发布所有收到的明信片在我们的虚拟明信片墙上。
安装
如果您正在使用PHP 7,请安装此包的v6.x版本。
您可以通过composer安装此包
composer require spatie/laravel-responsecache
包将自动注册自己。
您可以使用以下命令发布配置文件
php artisan vendor:publish --tag="responsecache-config"
这是发布配置文件的内容
// config/responsecache.php return [ /* * Determine if the response cache middleware should be enabled. */ 'enabled' => env('RESPONSE_CACHE_ENABLED', true), /* * The given class will determinate if a request should be cached. The * default class will cache all successful GET-requests. * * You can provide your own class given that it implements the * CacheProfile interface. */ 'cache_profile' => Spatie\ResponseCache\CacheProfiles\CacheAllSuccessfulGetRequests::class, /* * Optionally, you can specify a header that will force a cache bypass. * This can be useful to monitor the performance of your application. */ 'cache_bypass_header' => [ 'name' => env('CACHE_BYPASS_HEADER_NAME', null), 'value' => env('CACHE_BYPASS_HEADER_VALUE', null), ], /* * When using the default CacheRequestFilter this setting controls the * default number of seconds responses must be cached. */ 'cache_lifetime_in_seconds' => env('RESPONSE_CACHE_LIFETIME', 60 * 60 * 24 * 7), /* * This setting determines if a http header named with the cache time * should be added to a cached response. This can be handy when * debugging. */ 'add_cache_time_header' => env('APP_DEBUG', true), /* * This setting determines the name of the http header that contains * the time at which the response was cached */ 'cache_time_header_name' => env('RESPONSE_CACHE_HEADER_NAME', 'laravel-responsecache'), /* * This setting determines if a http header named with the cache age * should be added to a cached response. This can be handy when * debugging. * ONLY works when "add_cache_time_header" is also active! */ 'add_cache_age_header' => env('RESPONSE_CACHE_AGE_HEADER', false), /* * This setting determines the name of the http header that contains * the age of cache */ 'cache_age_header_name' => env('RESPONSE_CACHE_AGE_HEADER_NAME', 'laravel-responsecache-age'), /* * Here you may define the cache store that should be used to store * requests. This can be the name of any store that is * configured in app/config/cache.php */ 'cache_store' => env('RESPONSE_CACHE_DRIVER', 'file'), /* * Here you may define replacers that dynamically replace content from the response. * Each replacer must implement the Replacer interface. */ 'replacers' => [ \Spatie\ResponseCache\Replacers\CsrfTokenReplacer::class, ], /* * If the cache driver you configured supports tags, you may specify a tag name * here. All responses will be tagged. When clearing the responsecache only * items with that tag will be flushed. * * You may use a string or an array here. */ 'cache_tag' => '', /* * This class is responsible for generating a hash for a request. This hash * is used to look up an cached response. */ 'hasher' => \Spatie\ResponseCache\Hasher\DefaultHasher::class, /* * This class is responsible for serializing responses. */ 'serializer' => \Spatie\ResponseCache\Serializers\DefaultSerializer::class, ];
最后,您应该安装提供的中间件\Spatie\ResponseCache\Middlewares\CacheResponse::class
和\Spatie\ResponseCache\Middlewares\DoNotCacheResponse
。
对于laravel 11.x及更高版本
将中间件定义添加到引导应用程序。
// bootstrap/app.php ->withMiddleware(function (Middleware $middleware) { ... $middleware->web(append: [ ... \Spatie\ResponseCache\Middlewares\CacheResponse::class, ]); ... $middleware->alias([ ... 'doNotCacheResponse' => \Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class, ]); })
对于laravel 10.x及更早版本
将中间件定义添加到http内核。
// app/Http/Kernel.php ... protected $middlewareGroups = [ 'web' => [ ... \Spatie\ResponseCache\Middlewares\CacheResponse::class, ], ... protected $middlewareAliases = [ ... 'doNotCacheResponse' => \Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class, ];
用法
基本用法
默认情况下,该包将缓存所有成功的GET
请求一周。登录用户将各自有自己的缓存。如果这是您需要的,那么您就完成了:安装ResponseCacheServiceProvider
就足够了。
清除缓存
手动清除
可以使用以下命令清除整个缓存
ResponseCache::clear();
这将清除在配置文件中指定的缓存存储中的所有内容。
使用控制台命令
同样可以通过执行以下artisan命令来实现
php artisan responsecache:clear
使用模型事件
您可以通过模型事件来清除缓存,每次模型被保存或删除时。以下是一个示例。
namespace App\Traits; use Spatie\ResponseCache\Facades\ResponseCache; trait ClearsResponseCache { public static function bootClearsResponseCache() { self::created(function () { ResponseCache::clear(); }); self::updated(function () { ResponseCache::clear(); }); self::deleted(function () { ResponseCache::clear(); }); } }
忘记一个或多个特定的URI
您可以使用以下命令忘记特定的URI
// Forget one ResponseCache::forget('/some-uri'); // Forget several ResponseCache::forget(['/some-uri', '/other-uri']); // Equivalent to the example above ResponseCache::forget('/some-uri', '/other-uri');
当您不在您的缓存配置中使用cacheNameSuffix
时,ResponseCache::forget
方法才会起作用;使用ResponseCache::selectCachedItems
来处理cacheNameSuffix
。
忘记一组缓存项
您可以使用ResponseCache::selectCachedItems()
来指定应该忘记哪些缓存项。
// forgetting all PUT responses of /some-uri ResponseCache::selectCachedItems()->withPutMethod()->forUrls('/some-uri')->forget(); // forgetting all PUT responses of multiple endpoints ResponseCache::selectCachedItems()->withPutMethod()->forUrls(['/some-uri','/other-uri'])->forget(); // this is equivalent to the example above ResponseCache::selectCachedItems()->withPutMethod()->forUrls('/some-uri','/other-uri')->forget(); // forget /some-uri cached with "100" suffix (by default suffix is user->id or "") ResponseCache::selectCachedItems()->usingSuffix('100')->forUrls('/some-uri')->forget(); // all options combined ResponseCache::selectCachedItems() ->withPutMethod() ->withHeaders(['foo'=>'bar']) ->withCookies(['cookie1' => 'value']) ->withParameters(['param1' => 'value']) ->withRemoteAddress('127.0.0.1') ->usingSuffix('100') ->usingTags('tag1', 'tag2') ->forUrls('/some-uri', '/other-uri') ->forget();
cacheNameSuffix
取决于您的缓存配置,默认是用户ID,如果没有认证则为空字符串。
防止请求被缓存
可以通过使用doNotCacheResponse
中间件来忽略请求。这个中间件可以被分配到路由和控制器上。
使用这个中间件,我们的路由可以免于被缓存。
// app/Http/routes.php Route::get('/auth/logout', ['middleware' => 'doNotCacheResponse', 'uses' => 'AuthController@getLogout']);
或者,你可以在控制器中添加这个中间件
class UserController extends Controller { public function __construct() { $this->middleware('doNotCacheResponse', ['only' => ['fooAction', 'barAction']]); } }
故意绕过缓存
你可以故意并且安全地绕过缓存,并确保你始终收到最新的响应。这在你需要分析某个端点或调试响应时可能很有用。无论如何,你只需要设置CACHE_BYPASS_HEADER_NAME
和CACHE_BYPASS_HEADER_VALUE
环境变量,然后在执行请求时使用这个自定义头即可。
创建自定义缓存配置文件
为了确定哪些请求应该被缓存以及缓存多长时间,使用了一个缓存配置类。处理这些问题的默认类是Spatie\ResponseCache\CacheProfiles\CacheAllSuccessfulGetRequests
。
你可以通过实现 Spatie\ResponseCache\CacheProfiles\CacheProfile
接口来创建自己的缓存配置类。让我们看看这个接口
interface CacheProfile { /* * Determine if the response cache middleware should be enabled. */ public function enabled(Request $request): bool; /* * Determine if the given request should be cached. */ public function shouldCacheRequest(Request $request): bool; /* * Determine if the given response should be cached. */ public function shouldCacheResponse(Response $response): bool; /* * Return the time when the cache must be invalidated. */ public function cacheRequestUntil(Request $request): DateTime; /** * Return a string to differentiate this request from others. * * For example: if you want a different cache per user you could return the id of * the logged in user. * * @param \Illuminate\Http\Request $request * * @return mixed */ public function useCacheNameSuffix(Request $request); }
缓存特定路由
你不仅可以注册cacheResponse
中间件为全局中间件,也可以将其注册为路由中间件。
protected $middlewareAliases = [ ... 'cacheResponse' => \Spatie\ResponseCache\Middlewares\CacheResponse::class, ];
使用路由中间件时,你可以指定这些路由应该缓存多少秒
// cache this route for 5 minutes Route::get('/my-special-snowflake', 'SnowflakeController@index')->middleware('cacheResponse:300'); // cache all these routes for 10 minutes Route::group(function() { Route::get('/another-special-snowflake', 'AnotherSnowflakeController@index'); Route::get('/yet-another-special-snowflake', 'YetAnotherSnowflakeController@index'); })->middleware('cacheResponse:600');
使用标签
如果你的缓存驱动程序支持标签,你可以在应用中间件时指定一个标签列表。
// add a "foo" tag to this route with a 300 second lifetime Route::get('/test1', 'SnowflakeController@index')->middleware('cacheResponse:300,foo'); // add a "bar" tag to this route Route::get('/test2', 'SnowflakeController@index')->middleware('cacheResponse:bar'); // add both "foo" and "bar" tags to these routes Route::group(function() { Route::get('/test3', 'AnotherSnowflakeController@index'); Route::get('/test4', 'YetAnotherSnowflakeController@index'); })->middleware('cacheResponse:foo,bar');
清除带标签的内容
你可以清除被分配了标签或标签列表的响应。例如,这个语句会移除上面的'/test3'
和'/test4'
路由
ResponseCache::clear(['foo', 'bar']);
相反,这个语句只会移除'/test2'
路由
ResponseCache::clear(['bar']);
注意,这使用了Laravel的内置缓存标签功能,这意味着路由也可以以通常的方式清除
Cache::tags('special')->flush();
事件
你可以使用几个事件来监控和调试应用程序中的响应缓存。
ResponseCacheHit
Spatie\ResponseCache\Events\ResponseCacheHit
当请求通过ResponseCache
中间件并且找到了缓存响应并返回时,会触发这个事件。
CacheMissed
Spatie\ResponseCache\Events\CacheMissed
当请求通过ResponseCache
中间件但没有找到或返回缓存响应时,会触发这个事件。
ClearingResponseCache 和 ClearedResponseCache
Spatie\ResponseCache\Events\ClearingResponseCache
Spatie\ResponseCache\Events\ClearedResponseCache
当responsecache:clear
开始和结束时,分别会触发这些事件。
创建一个 Replacer
为了用动态内容替换缓存内容,你可以创建一个替换器。默认情况下,我们在配置文件中添加了一个CsrfTokenReplacer
。
你可以通过实现Spatie\ResponseCache\Replacers\Replacer
接口来创建自己的替换器。让我们看看这个接口
interface Replacer { /* * Prepare the initial response before it gets cached. * * For example: replace a generated csrf_token by '<csrf-token-here>' that you can * replace with its dynamic counterpart when the cached response is returned. */ public function prepareResponseToCache(Response $response): void; /* * Replace any data you want in the cached response before it gets * sent to the browser. * * For example: replace '<csrf-token-here>' by a call to csrf_token() */ public function replaceInCachedResponse(Response $response): void; }
之后,你可以在responsecache.php
配置文件中定义你的替换器
/*
* Here you may define replacers that dynamically replace content from the response.
* Each replacer must implement the Replacer interface.
*/
'replacers' => [
\Spatie\ResponseCache\Replacers\CsrfTokenReplacer::class,
],
自定义序列化器
序列化器负责将响应序列化以便存储在缓存中。它还负责从缓存中重建响应。
默认序列化器Spatie\ResponseCache\Serializer\DefaultSerializer
在大多数情况下都能正常工作。
如果你有一些特殊的序列化需求,你可以在配置文件的serializer
键中指定一个自定义序列化器。任何实现Spatie\ResponseCache\Serializers\Serializer
的类都可以使用。这个接口看起来是这样的
namespace Spatie\ResponseCache\Serializers; use Symfony\Component\HttpFoundation\Response; interface Serializer { public function serialize(Response $response): string; public function unserialize(string $serializedResponse): Response; }
测试
你可以使用以下命令运行测试
composer test
替代方案
- Barry Vd. Heuvel 开发了一个利用 HttpCache 缓存响应的 软件包。
- Joseph Silber 创建了 Laravel Page Cache,可以将缓存写入磁盘,并允许 Nginx 读取它们,这样 PHP 甚至都不需要再启动了。
变更日志
请参阅 变更日志 了解最近有哪些变化。
贡献
请参阅 贡献指南 了解详细信息。
安全
如果您发现了与安全相关的错误,请通过 security@spatie.be 邮件发送,而不是使用问题跟踪器。
致谢
特别感谢 Caneco 为我们的标志 ✨
许可证
MIT 许可证 (MIT)。请参阅 许可证文件 了解更多信息。