6

我有一个小型图像生成器作为我的 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

我的问题是我的浏览器(chrome,未在其他浏览器中测试)仍然拒绝简单地获取本地缓存版本,而是再次访问服务器。

我花了大约半个小时来寻找关于这个主题的其他问题,所有这些问题都给了我答案,我将这些答案纳入了上述代码。所以虽然我知道有类似的问题,但这个问题是上述源代码所独有的。

我的问题是,我做错了什么会导致浏览器不缓存文件?

4

2 回答 2

4

An alternative method to this would be to check for the 'If-Modified-Since' request header as it will only be present if the browser already has the file.

If it is present, then you know the file is already created and can respond with a link to it, otherwise run your code above. Something like this...

// 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 M Y H:i:s \G\M\T', time() + $image->get_expires() ) );
    header( 'Content-Type: image/jpeg');

    print file_get_contents( $image->get_full_path() ); 
}
于 2013-08-10T16:07:54.743 回答
4

您似乎仍在告诉 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;
    }
于 2015-01-16T16:42:41.507 回答