Symfony returning HTTP 304 locally, but HTTP 200 for matching ETag in production
Due to a heavy API call taking upwards of 20 seconds, I have enabled computation of ETag for that resource and pre-compute the ETag before doing any heavy DB work to be able to return early. This works fine using the PHP development server (I can debug step through the code and see the HTTP status codes being correct) and I get HTTP 304, but for some reason it does not seem to take effect when deploying to production and I wonder how I can debug it?
The curl call sees the right If-None-Match ETag being sent, but still I get HTTP 200 and the same Etag back instead of HTTP 304.
> if-none-match: W/"5e3f549935516374f93531655b66aaf4"
< HTTP/2 200
< date: Mon, 10 Jan 2022 16:21:55 GMT
< content-type: application/json
< server: nginx
< cache-control: private
< etag: W/"5e3f549935516374f93531655b66aaf4"
As this works locally (using the Symfony development server: ./bin/console server:run), but not when deploying to production, I suspect it is something to do with which $kernel is running, but I have followed the caching guide and changed both web/app.php and web/app_dev.php to include the following:
$kernel = new AppKernel('prod', false);
// enable caching
// all authorized endpoints are automatically no-cache by default
$kernel = new AppCache($kernel);
// When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter
Request::enableHttpMethodParameterOverride();
Any idea on what could be wrong?
The code in question looks something like this:
$computed = $this->getEtagAndTimestampForCatalogByUserAndType($user, $catalog_type);
$etag = $computed['etag'];
// Save the DB some work and avoid recomputing already here
if (self::matchingEtag($request, $etag)) {
return $this->json(null, Response::HTTP_NOT_MODIFIED);
}
// bla bla domain code
$responseData = doHeavyDBStuff();
$jsonResponse = $this->json($responseData);
$jsonResponse->setEtag($etag);
return $jsonResponse;
Since enabling the HttpCache class in Symfony removes all caching headers before they reach AppKernel using this "early-exit" is not usually possible, but I chose to use a little trick where I fetch the headers in AppCache.php and assign them to custom headers (X-If-Modified-Since) that I then can compare in my etag comparison above:
class AppCache extends HttpCache
{
const CUSTOM_IF_NONE_MATCH_HEADER = 'x-if_none_match';
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
/* Work around the fact that the caching layer removes the headers. This allows for custom caching strategies */
$request->headers->add(array(AppCache::CUSTOM_IF_NONE_MATCH_HEADER => $request->headers->get('if_none_match')));
return parent::handle($request, $type, $catch);
}
In production this is running on
- PHP FPM behind Nginx.
- Symfony 3.4
- PHP 7.2
from Recent Questions - Stack Overflow https://ift.tt/3nbryUu
https://ift.tt/eA8V8J
Comments
Post a Comment