本文目录导读:

是的,在 Laravel 中通常使用中间件来设置缓存头(Cache-Control、Expires 等),这是最优雅、最符合 Laravel 设计模式的做法。
为什么用中间件?
- 关注点分离:缓存策略属于 HTTP 响应头处理,不应写在控制器业务逻辑里
- 可复用:多个路由/控制器可以共用同一个缓存策略
- 灵活控制:可以针对不同路由设置不同的缓存时长
- 条件判断:可以根据用户登录状态、环境等动态决定是否缓存
实现方式
自定义中间件
// app/Http/Middleware/SetCacheHeaders.php
namespace App\Http\Middleware;
use Closure;
use Symfony\Component\HttpFoundation\Response;
class SetCacheHeaders
{
public function handle($request, Closure $next, $maxAge = 3600)
{
/** @var Response $response */
$response = $next($request);
// 只缓存 GET 请求
if (!$request->isMethod('GET')) {
return $response;
}
// 设置缓存头
$response->headers->set('Cache-Control', sprintf(
'public, max-age=%d, s-maxage=%d',
$maxAge,
$maxAge * 2 // CDN 可以缓存更久
));
// 设置 Expires 头
$response->headers->set(
'Expires',
gmdate('D, d M Y H:i:s', time() + $maxAge) . ' GMT'
);
return $response;
}
}
注册中间件
// app/Http/Kernel.php
protected $routeMiddleware = [
// ... 其他中间件
'cache.headers' => \App\Http\Middleware\SetCacheHeaders::class,
];
在路由中使用
// 方式一:在路由定义中指定
Route::middleware('cache.headers:3600')->group(function () {
Route::get('/articles', [ArticleController::class, 'index']);
Route::get('/articles/{id}', [ArticleController::class, 'show']);
});
// 方式二:在控制器中使用
class ArticleController extends Controller
{
public function __construct()
{
// 对指定方法应用缓存
$this->middleware('cache.headers:300')->only(['index', 'show']);
}
}
更高级的方案:使用缓存标签
如果需要对不同资源设置不同缓存策略,可以使用中间件参数:
// 自定义中间件支持多个标签
class SetCacheHeaders
{
public function handle($request, Closure $next, ...$params)
{
$response = $next($request);
// 解析参数
$maxAge = 3600;
$tags = [];
foreach ($params as $param) {
if (is_numeric($param)) {
$maxAge = (int) $param;
} else {
$tags[] = $param;
}
}
// 可以根据 tags 做更精细的控制
// 不同的标签代表不同的内容类型
if (in_array('user-specific', $tags) && auth()->check()) {
// 用户私有内容,加 private 缓存
$response->headers->set('Cache-Control', 'private, max-age=60');
} else {
$response->headers->set('Cache-Control', sprintf(
'public, max-age=%d', $maxAge
));
}
return $response;
}
}
// 路由使用
Route::middleware('cache.headers:300,public,articles')->get('/api/articles', ...);
内置中间件:CacheControl 和 SetCacheHeaders
Laravel 本身也提供了一些相关中间件:
cache.headers(Laravel 自带)
// Laravel 已经有一个内置的 cache.headers 中间件
// 用法略有不同
Route::get('/articles', function () {
return response()->json($articles);
})->middleware('cache.headers:public;max_age=3600;etag');
或者使用 response()->withHeaders()
// 在控制器中
return response()
->json($data)
->withHeaders([
'Cache-Control' => 'public, max-age=3600',
'ETag' => md5(serialize($data)),
]);
实践建议
- GET 请求:通常需要缓存(公共资源 3600s,用户私有资源 60s)
- :使用 ETag + 304 Not Modified
- API 接口:建议设置短缓存(如 60-300 秒)
- 静态资源:由 Nginx/CDN 处理,Laravel 不介入
- 登录用户:区分
public和private缓存
完整示例:条件缓存中间件
class ConditionalCacheHeaders
{
public function handle($request, Closure $next, $publicMaxAge = 3600)
{
$response = $next($request);
// 只缓存成功的 GET 响应
if ($request->isMethod('GET') && $response->isSuccessful()) {
// 如果是登录用户,使用 private 缓存
$cacheType = auth()->check() ? 'private' : 'public';
// 动态计算 max-age
$maxAge = auth()->check() ? 60 : $publicMaxAge;
$response->headers->set('Cache-Control', sprintf(
'%s, max-age=%d',
$cacheType,
$maxAge
));
// 添加 ETag 支持条件请求
$response->headers->set('ETag', '"' . md5($response->getContent()) . '"');
}
return $response;
}
}
是的,强烈推荐使用中间件,把缓存策略作为横切关注点集中管理,让你的控制器保持干净,专注于业务逻辑。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播