我在PHP中实现HTTP条件获取答案是否正常?

Ale*_*exV 8 php caching header http http-headers

经过大量搜索,阅读我发现的每一个教程并在这里提出一些问题后,我终于设法回答了if-none-match和if-modified-自HTTP请求以来的错误(至少我认为).

要快速回顾一下,这就是我在每个可缓存页面上所做的事情:

session_cache_limiter('public'); //Cache on clients and proxies
session_cache_expire(180); //3 hours
header('Content-Type: ' . $documentMimeType . '; charset=' . $charset);
header('ETag: "' . $eTag . '"'); //$eTag is a MD5 of $currentLanguage + $lastModified
if ($isXML)
    header('Vary: Accept'); //$documentMimeType can be either application/xhtml+xml or text/html for XHTML (based on $_SERVER['HTTP_ACCEPT'])
header('Last-Modified: ' . $lastModified);
header('Content-Language: ' . $currentLanguage);
Run Code Online (Sandbox Code Playgroud)

此外,每个页面都有自己的URL(适用于所有语言).例如,"index.php"将在英文URL"/ en/home"和法语"/ fr/accueil"下提供.

我的一个大问题是回答"304 Not Modified"到if-none-match和if-modified-since,因为HTTP请求只在需要时.

我发现的最好的文档是:http: //rithiur.anthd.com/tutorials/conditionalget.php

这就是我所做的实现(这段代码在可以缓存的页面上称为ASAP):

$ifNoneMatch = array_key_exists('HTTP_IF_NONE_MATCH', $_SERVER) ? $_SERVER['HTTP_IF_NONE_MATCH'] : false;
$ifModifiedSince = array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : false;

if ($ifNoneMatch !== false && $ifModifiedSince !== false)
{
    //Both if-none-match and if-modified-since were received.
    //They must match the document values in order to send a HTTP 304 answer.
    if ($ifNoneMatch == $eTag && $ifModifiedSince == $lastModified)
    {
        header('Not Modified', true, 304);
        exit();
    }
}
else
{
    //Only one header received, it it match the document value, send a HTTP 304 answer.
    if (($ifNoneMatch !== false && $ifNoneMatch == $eTag) || ($ifModifiedSince !== false && $ifModifiedSince == $lastModified))
    {
        header('Not Modified', true, 304);
        exit();
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题有两个:

  • 这是正确的方法吗?我的意思是当if-none-match和if-modified-since被发送时,两者必须匹配才能回答304,如果只发送了两个中的一个,只匹配这个就可以发送304了吗?
  • 当在这里描述的上下文中使用时,这两个片段是否是公共缓存友好的(我的意思是代理 Web浏览器上的缓存友好)?

顺便说一下,我只使用PHP 5.1.0+(我不支持低于此版本的版本).

编辑:添加赏金......我期待质量答案.如果你在猜什么,不要回答/投票!

St.*_*and 22

以下是可能有用的功能:

function isModified($mtime, $etag) {
    return !( (
        isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
        && 
        strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $mtime
    ) || (
        isset($_SERVER['HTTP_IF_NONE_MATCH'])
        && 
        $_SERVER['HTTP_IF_NONE_MATCH'] == $etag
    ) ) ;
}
Run Code Online (Sandbox Code Playgroud)

我建议你看一下下面的文章:http://www.peej.co.uk/articles/http-caching.html

更新:

[AlexV]甚至可以在同一时间接收if-none-match和if-modified-?

你绝对可以同时设置.然而:

如果没有任何实体标签匹配,则服务器可以执行所请求的方法,就像If-None-Match头字段不存在一样,但是也必须忽略请求中的任何If-Modified-Since头字段.也就是说,如果没有实体标签匹配,那么服务器绝不能返回304(未修改)响应.

RFC2616#14.26

示例值(W代表'弱';在RFC2616#13.3.3中阅读更多内容):

If-None-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
If-None-Match: W/"xyzzy", W/"r2d2xxxx", W/"c3piozzzz"
If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT
If-None-Match: *
Run Code Online (Sandbox Code Playgroud)

作为特殊情况,值"*"匹配资源的任何当前实体.

  • 另请注意RFC2616(HTTP1.1)规范第14.26节关于If-None-Match的语法.这个和原始问题都不允许多个etag值或"*".话虽这么说,这个假设可能是99.9%的时间. (3认同)