Laravel 5如何全局设置Cache-Control HTTP头?

17

我的Laravel应用程序默认为每个站点返回Cache-Control: no-cache, private HTTP头。我该如何更改这个行为?

P.S.:这不是PHP.ini的问题,因为将session.cache_limiter更改为empty/public并没有改变什么。

3个回答

27

Laravel 5.6+

现在不再需要添加自定义中间件了。

SetCacheHeaders 中间件已经随 Laravel 自带,并且别名为 cache.headers

这个中间件的好处是它仅适用于 GETHEAD 请求 - 它不会缓存 POSTPUT 请求,因为你几乎永远不想这样做。

您可以通过更新您的 RouteServiceProvider 轻松地全局应用此功能:

protected function mapWebRoutes()
{
    Route::middleware('web')
        ->middleware('cache.headers:private;max_age=3600') // added this line
        ->namespace($this->namespace)
        ->group(base_path('routes/web.php'));
}

protected function mapApiRoutes()
{
    Route::prefix('api')
        ->middleware('api')
        ->middleware('cache.headers:private;max_age=3600') // added this line
        ->namespace($this->namespace)
        ->group(base_path('routes/api.php'));
}

我不建议这样做。相反,就像任何中间件一样,您可以轻松地应用于特定的端点、组或控制器本身内部,例如:

我不推荐那样做。而是像任何中间件一样,你可以很容易地应用到特定的端点、组或者是在控制器本身内部中使用,例如:

Route::middleware('cache.headers:private;max_age=3600')->group(function() {
    Route::get('cache-for-an-hour', 'MyController@cachedMethod');
    Route::get('another-route', 'MyController@alsoCached');
    Route::get('third-route', 'MyController@alsoAlsoCached');
});

请注意选项是用分号而不是逗号分隔的,并且连字符会被替换为下划线。此外,Symfony仅支持有限数量的选项:

'etag'、'last_modified'、'max_age'、's_maxage'、'private'、'public'、'immutable'

换句话说,您不能简单地复制并粘贴标准的Cache-Control头值,您需要更新格式:

CacheControl format:       private, no-cache, max-age=3600
  ->
Laravel/Symfony format:    private;max_age=3600

1
@AlmostPitt.. 我也遇到了这个问题。我认为Sympony不支持这个。他们最近进行了更新。https://github.com/symfony/symfony/issues/35720 - Supunsam
@AdamJones 是的,那是我给出的 Route::middleware 示例。虽然只列出了一个路由,但它在一个组内,你可以添加更多。 - andrewtweber
嗨@andrewtweber,感谢您的回复,但我真的想在/routes/web.php文件中针对一些特定路由进行操作。您有Route::group定义如何在其中定义标头的示例吗? - AdamJones
@AdamJones 我更新了例子,现在更清晰了吗?你只需要在 group() 调用之前链接中间件。 - andrewtweber
@andrewtweber... 我的路由组定义如下:Route::middleware(['forAccountHoldersAjaxOnly'])->group( function() {我该如何添加一个头部来停止所有缓存?我不确定语法,也找不到任何网站上的解释。 - AdamJones
显示剩余3条评论

18

Laravel 5.5 <

你可以设置一个全局中间件来实现这个功能。例如:

<?php

namespace App\Http\Middleware;

use Closure;

class CacheControl
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        $response->header('Cache-Control', 'no-cache, must-revalidate');
        // Or whatever you want it to be:
        // $response->header('Cache-Control', 'max-age=100');

        return $response;
    }
}

然后只需在Kernel文件中将其注册为全局中间件:

protected $middleware = [
    ....
    \App\Http\Middleware\CacheControl::class
];

5

如果您希望写更少的代码,这里有另一种方法可以在不添加额外步骤的情况下向响应添加标头。

在上面的例子中,我创建了一个中间件,以防止路由被缓存在最终用户浏览器中。

<?php

class DisableRouteCache
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        return $next($request)->withHeaders([
            "Pragma" => "no-cache",
            "Expires" => "Fri, 01 Jan 1990 00:00:00 GMT",
            "Cache-Control" => "no-cache, must-revalidate, no-store, max-age=0, private",
        ]);
    }
}

来源:将标头附加到响应中


缓存控制选项是多余的,有些还相互矛盾。例如,no-store 表示不在任何缓存中存储资源,但是 no-cache 表示可以缓存,但必须重新验证源。然后你有 must-revalidate,在这种情况下,它被 no-cache 隐含了,因为 max-age 是 0(资源永远不新鲜)。然后你有 max-age=0... 但是 no-store 表示根本不缓存。然后你有 private,表示可以将资源存储在私有缓存中,如浏览器...但 no-cache 又相互矛盾。 - benbotto
两年过去了,它仍然像我预期的那样正常工作。 - Anwar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接