My team and I are working on a Laravel API which communicates with a Vue.js frontend that uses the Apollo client to consume the GraphQL responses.
We have an issue with cache-control headers being added to the response.
Apollo cannot cache the contents because the response contains this header:
Cache-Control: no-cache, private
In php.ini, we have this to disable sending cache-control headers by PHP:
; Set to {nocache,private,public,} to determine HTTP caching aspects
; or leave this empty to avoid sending anti-caching headers.
; http://php.net/session.cache-limiter
session.cache_limiter =
In the nginx config we cannot find anything that is setting those headers. I checked the global nginx.conf and config file we setup in sites/available.
I can add this to the nginx config, but it will only add another header:
add_header Cache-Control "public";
Cache-Control: no-cache, private
Cache-Control: public
If this header is not coming from PHP or nginx, then where could it be coming from? And how can I remove or overwrite it?
in any middleware you can use this example
public function handle($request, Closure $next)
{
$response= $next($request);
return $response->header('X-TEST-HEADER','test header value');
}
but i do not know this fix your problem
you can do this by Adding in your .htaccess if you are using apache
Header always set Cache-Control "no-cache, public"
so it will remove the Cache-Control:private and give the header response as
Cache-Control:no-cache , public
In Laravel, the Cache-Control: no-cache, private
header is set in the vendor package Symfony http-foundation by the following logic:
/**
* Returns the calculated value of the cache-control header.
*
* This considers several other headers and calculates or modifies the
* cache-control header to a sensible, conservative value.
*
* @return string
*/
protected function computeCacheControlValue()
{
if (!$this->cacheControl) {
if ($this->has('Last-Modified') || $this->has('Expires')) {
return 'private, must-revalidate'; // allows for heuristic expiration (RFC 7234 Section 4.2.2) in the case of "Last-Modified"
}
// conservative by default
return 'no-cache, private';
}
$header = $this->getCacheControlHeader();
if (isset($this->cacheControl['public']) || isset($this->cacheControl['private'])) {
return $header;
}
// public if s-maxage is defined, private otherwise
if (!isset($this->cacheControl['s-maxage'])) {
return $header.', private';
}
return $header;
}
Source: Laravel 5.6 vendor/symfony/http-foundation/ResponseHeaderBag.php
lines 269-299
As the OP stated in his comment to @ the_hasanov's answer , the header can be overwritten by implementing a middleware.
php artisan make:middleware CachePolicy
edit the new app/Http/Middleware/Cachepolicy.php
so that it reads:
<?php
namespace App\Http\Middleware;
use Closure;
class CachePolicy
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
// return $next($request);
$response= $next($request);
return $response->header('Cache-Control','no-cache, public');
}
}
app/http/Kernel.php
to include the new middleware:...
protected $middleware = [
...
\App\Http\Middleware\CachePolicy::class,
];
...
Please note that no cache
does NOT mean " don't cache ", which is no-store
, no cache
"allows caches to store a response but requires them to revalidate it before reuse." Check here https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control for detailed information.
To revalidate, your server response should have etag
or Last-Modified
. Check here https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching for detailed information. For example, at the section starts with "Validation is done by using a conditional request that includes an If-Modified-Since
or If-None-Match
request header." So your server probably don't have those fields for revalidation.
The private
means "cache that exists in the client. It is also called local cache or browser cache. It can store and reuse personalized content for a single user."
@Vardkin's answer correctly pointed out it is in computeCacheControlValue() that set those fields,
if (!$this->cacheControl) {
if ($this->has('Last-Modified') || $this->has('Expires')) {
return 'private, must-revalidate'; // allows for heuristic expiration (RFC 7234 Section 4.2.2) in the case of "Last-Modified"
}
// conservative by default
return 'no-cache, private';
}
I want to add that must-revalidate
also explained in those articles I attached.
HTTP allows caches to reuse stale responses when they are disconnected from the origin server. must-revalidate is a way to prevent this from happening
Stale responses are not immediately discarded. HTTP has a mechanism to transform a stale response into a fresh one by asking the origin server...Validation is done by using a conditional request
But I never figure how much difference between no-cache
& must-revalidate
since they all need to validate.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.