Make PHP page return “304 Not Modified” if it hasn't been modified

独自空忆成欢 提交于 2019-12-18 04:18:07

问题


I have a PHP file that will return the same thing with the same $_GET parameters every time -- it's deterministic.

Unfortunately for efficiency (this file is requested very often), Apache defaults to a "200 OK" response whenever a PHP page is requested, making the user download the file again.

Is there any way to send a 304 Not Modified header if and only if the parameters are the same?

Bonus: Can I set an expiry time on it, so that if the cached page is more than, say, three days old, it sends a "200 OK" response?


回答1:


Without caching the page yourself (or at least its Etag) you cannot really make use of the 304. A full fledged caching algorithm is somewhat out of scope, but the general idea:

<?php 
function getUrlEtag($url){
    //some logic to get an etag, possibly stored in memcached / database / file etc.
}
function setUrlEtag($url,$etag){
    //some logic to get an etag, possibly stored in memcached / database / file etc.
}
function getPageCache($url,$etag=''){
    //[optional]some logic to get the page from cache instead, possibly not even using etag
}
function setPageCache($url,$content,$etag=''){
    //[optional]some logic to save the page to cache, possibly not even using etag
}
ob_start();
$etag = getUrlEtag($_SERVER['REQUEST_URI']);
if(isset($_SERVER['HTTP_IF_NONE_MATCH']) && trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag) { 
    header("HTTP/1.1 304 Not Modified"); 
    exit; 
}
if(($content=getPageCache($_SERVER['REQUEST_URI'],$etag))!==false){
    echo $content;
    exit;
}
?>
//the actual page
<?php
$content = ob_get_clean();
setUrlEtag($_SERVER['REQUEST_URI'],$etag=md5($url.$content));
function setPageCache($_SERVER['REQUEST_URI'],$content,$etag);
header("Etag: $etag");
echo $content;
?>

All common pitfalls apply: you can possibly not display cache pages for logged in users, a caching of partial content could be more desirable, you are yourself responsible for preventing stale content in the cache (possibly using triggers in backend or database on modifications, or just playing around with the getUrlEtag logic), etc. etc.

You could also play around with HTTP_IF_MODIFIED_SINCE if that's easier to control.




回答2:


In general, you return HTTP status codes using the Header function:

Header("HTTP/1.1 304 Not Modified");
exit();

However, this alone isn't enough.

The problem is that you don't know how requested the file, so you'll need a bit of browser cooperation.

You can look for If-modified-since headers in the incoming request, and return the appropriate status code if it's present and within date range.

If you send a proper Expires header when you initially generate the PHP, then the browser or proxy cache may decide to not fetch the request at all (although more likely, they'll set the If-modified-since header). Without an Expires header, the browser will likely always re-try the full request.

For more information, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html and search for "14.25"

The browser will do the mapping of GET parameters to cached copy, btw. You don't need to do any work there.




回答3:


Have you tried header("HTTP/1.0 304 Not Modified"); in your PHP code that is getting called? If unfamiliar you will want to put that in your code BEFORE you start outputting anything to the buffer.

http://php.net/manual/en/function.header.php




回答4:


This script will render the whole PHP Script again, but after that, it checks if the ETag ist equivalent to the MD5 of the output string and if so, it sends a 304 and no bandwith is used. You could also create such a thing with the MD5 of all the QueryString etc. and store it somewhere, you would not need to recreate the output content (even faster)

function sanitize_output($buffer) {
    $headers = apache_request_headers();
    $tt5=md5($buffer);  
    header('ETag: '.$tt5);
    if (isset($headers['If-None-Match']) && $headers['If-None-Match']===$tt5) {
        header('HTTP/1.1 304 Not Modified');
        header('Connection: close');
        exit();
    }
    return $buffer;
}

ob_start("sanitize_output");


来源:https://stackoverflow.com/questions/2978496/make-php-page-return-304-not-modified-if-it-hasnt-been-modified

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!