У меня есть небольшой генератор изображений как часть моего приложения laravel4. Для создания изображения требуется около 700 мс, поэтому я начал кэшировать сгенерированный результат на моем сервере и вместо этого возвращать его в браузер, что экономит некоторое время.
Поскольку изображение никогда не будет меняться после создания, я хотел бы сказать браузеру кэшировать изображение локально, и я сделал это со следующим кодом:
$path = $cacheFolderPath . $cacheFileName; if (File::exists( $path )){ $response = Response::make(File::get($path)); $response->header('Content-Type', 'image/png'); $response->header('Content-Disposition', 'inline; filename="'.$cacheFileName.'"'); $response->header('Content-Transfer-Encoding', 'binary'); $response->header('Cache-Control', 'public, max-age=10800, pre-check=10800'); $response->header('Pragma', 'public'); $response->header('Expires', date(DATE_RFC822,strtotime(" 2 day")) ); $response->header('Last-Modified', date(DATE_RFC822, File::lastModified($path)) ); $response->header('Content-Length', filesize($path)); return $response; }
Это отправляет изображение с кодом состояния 200 OK
в браузер со следующими заголовками:
Cache-Control:max-age=10800, pre-check=10800, public Connection:Keep-Alive Content-Disposition:inline; filename="pie_0_normal.png" Content-Length:2129 Content-Transfer-Encoding:binary Content-Type:image/png Date:Wed, 07 Aug 2013 10:29:20 GMT Expires:Fri, 09 Aug 13 10:29:20 +0000 Keep-Alive:timeout=5, max=93 Last-Modified:Wed, 07 Aug 13 10:14:42 +0000 Pragma:public Server:Apache/2.4.3 (Win32) OpenSSL/1.0.1c PHP/5.4.7 Set-Cookie:laravel_session=767487mhf6j2btv3k01vu56174; expires=Wed, 07-Aug-2013 12:29:20 GMT; path=/; httponly X-Powered-By:PHP/5.4.7
Моя проблема заключается в том, что мой браузер (хром, не проверенный другими) по-прежнему отказывается просто захватить локальную кешированную версию и вместо этого снова обращается к серверу.
Я потратил около получаса на поиск других вопросов по этому вопросу, и все они дали мне ответы, которые я включил в вышеуказанный код. Поэтому, хотя я знаю, что есть похожие вопросы, этот является уникальным для вышеупомянутого исходного кода.
Мой вопрос: что я делаю неправильно, что приведет к тому, что файл не будет кэшироваться браузером?
Альтернативным методом для этого было бы проверить заголовок запроса «If-Modified-Since», поскольку он будет присутствовать только в том случае, если в браузере уже есть файл.
Если он присутствует, то вы знаете, что файл уже создан и может отвечать ссылкой на него, иначе запустите свой код выше. Что-то вроде этого…
// check if the client validating cache and if it is current if ( isset( $headers['If-Modified-Since'] ) && ( strtotime( $headers['If-Modified-Since'] ) == filemtime( $image->get_full_path() ) ) ) { // cache IS current, respond 304 header( 'Last-Modified: ' . $image->get_last_modified(), true, 304 ); } else { // not cached or client cache is older than server, respond 200 and output header( 'Last-Modified: ' . $image->get_last_modified(), true, 200 ); header( 'Content-Length: ' . $image->get_filesize() ); header( 'Cache-Control: max-age=' . $image->get_expires() ); header( 'Expires: '. gmdate('D, d MYH:i:s \G\M\T', time() + $image->get_expires() ) ); header( 'Content-Type: image/jpeg'); print file_get_contents( $image->get_full_path() ); }
По-видимому, вы все еще говорите Laravel, чтобы загрузить этот актив и отвечать на него как загрузку, вы можете предоставить заголовок Cache-Control, но это не имеет значения, потому что вы повторно генерируете этот актив каждый раз при загрузке изображения.
Я сам столкнулся с подобной проблемой и нашел, что лучший способ обслуживать изображения состоял в том, чтобы ввести статическую функцию в мое представление, например ImageController: fetchImage ($ image).
Затем метод будет проверять локальную папку, чтобы узнать, существует ли файл, а затем он просто вернет местоположение изображения, например: /img/1332.jpg … Если файл не существует, он создаст изображение , сохраните его в папке img и затем верните местоположение.
Это позволяет избежать использования laravel из-за того, что он должен выполнить новый (неактивный) ответ в виде загрузки. В любое время, когда изображение запрашивается, и вместо этого направляет браузер для загрузки ресурсов, которые уже кэшированы.
Это работало в моем случае, что …
if (App::environment('local')) { return 'http://placehold.it/150x150'; } $target_file = 'img_cache/'. $release_id .'.jpg'; if (file_exists($target_file)) return '/'.$target_file; else { $release = DB::(get release location on another server from db); if(!$release) return 'http://placehold.it/150x150'; $imageString = file_get_contents("http://pomed.promoonly.com/".$release[0]->image_src); file_put_contents($target_file, $imageString); return '/'.$target_file; }