php 中的 Laravel 标头和缓存

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18101176/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 08:14:24  来源:igfitidea点击:

Laravel Headers and Caching in php

phphttp-headerslaravellaravel-4http-caching

提问by carbontwelve

I have a small image generator as part of my laravel4 application. It takes about 700ms to generate the image and so I have started caching the generated result on my server and returning that to the browser instead which saves some time.

我有一个小型图像生成器作为我的 laravel4 应用程序的一部分。生成图像大约需要 700 毫秒,所以我已经开始在我的服务器上缓存生成的结果并将其返回到浏览器,这样可以节省一些时间。

As the image will never change once generated I wanted to tell the browser to cache the image locally and I have done this with the following code:

由于图像一旦生成就永远不会改变,我想告诉浏览器在本地缓存图像,我使用以下代码完成了此操作:

$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;
}

This sends an image with status code 200 OKto the browser with the following headers:

这会将带有状态代码的图像发送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

My issue is that my browser (chrome, not tested in others) still refuses to simply grab the local cached version and instead hits the server again.

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

I have spent about half an hour searching for other questions on this subject and all of them have given me answers which I have incorporated into the above code. So while I know that there are similar questions, this one is unique to the above source code.

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

My question is, what am I doing wrong that would result in the file not being cached by the browser?

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

采纳答案by darronz

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-Modified-Since”请求标头,因为它只有在浏览器已经拥有该文件时才会出现。

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() ); 
}

回答by Joey

It appears that you are still telling Laravel to download the asset and serve the response as a download, you can provide a Cache-Control header, but it does not matter because you are re-generating this asset each time the image is loaded.

看来您仍在告诉 Laravel 下载资产并将响应作为下载提供,您可以提供一个 Cache-Control 标头,但这并不重要,因为您每次加载图像时都会重新生成此资产。

I ran into a similar problem myself and found the best way to serve the images was to inject a static function into my view something like ImageController:fetchImage($image).

我自己遇到了类似的问题,并发现提供图像的最佳方法是将静态函数注入我的视图中,例如 ImageController:fetchImage($image)。

The method then will then check a local folder to see if the file exists and then it will just return the location of the image, something like: /img/1332.jpg... If the file does not exist it will create the image, save it to the img folder and then return the location.

然后该方法将检查本地文件夹以查看文件是否存在,然后它只会返回图像的位置,例如:/img/1332.jpg...如果文件不存在,它将创建图像,保存到img文件夹,然后返回位置。

This avoids laravel from ever having to serve up a brand new (uncached) response as a download EACH time the image is requested and instead directs the browser to load resources that are already cached.

这避免了 laravel 在每次请求图像时都必须提供全新的(未缓存的)响应作为下载,而是指示浏览器加载已经缓存的资源。

This worked in my case that is...

这在我的情况下是有效的......

    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;
    }