缓存动态生成的页面

Caching Dynamically Generated Pages

我们正在寻求加速我们的网站。更具体地说,我们希望降低 TTFB。我们的网站主要由基于 url 路径(提取主题)和 url 路径中的参数动态生成的页面组成。 这些条目被放入 sql 查询中,该查询从我们使用 php.

执行的数据库中提取所有正确的数据

这是问题所在:

这些查询可以完美地生成页面和与之相关的所有信息(例如标签)。 但是,每次访问者访问页面时重新运行代码会花费大量时间,从而导致 TTFB/server 响应时间过长。本质上,这些页面只需要每月使用 sql 查询更新一次。在此期间,应该可以将它们作为 preloaded/pregenerated 静态 HTML 页面提供(直到我们指示刷新)。我们目前正在使用 Cloudflare 作为 CDN,这在加快网站速度方面已经非常出色。现在,即使我们启用了 "Cache Everything" 的页面规则,我们仍然可以看到它重新运行 php 代码,包括 sql 查询。

问题:

有人知道实现缓存网站动态部分这一目标的好方法吗?是通过 Cloudflare 还是通过其他方式?我知道 Akamai 提供这项服务,但显然,将网站切换到另一个 CDN 会产生一些转换成本,我们对 Cloudflare 相当满意。

提前致谢!

如果您的网站有数百个页面,每天都有很多访问者,您可能需要为您的网站实施某种缓存机制以加快页面加载时间。每个客户端-服务器请求都包含多个数据库查询、服务器响应和增加整体页面加载时间的处理时间。最常见的解决方案是制作称为缓存文件的动态页面的副本,并将它们存储在单独的目录中,以后可以将其用作静态页面,而不是一次又一次地重新生成动态页面。 了解动态页面和缓存文件

缓存文件是由动态页面生成的静态副本,这些文件生成一次并存储在单独的文件夹中直到过期,当用户请求内容时,将提供相同的静态文件而不是动态生成的页面,因此绕过重新生成 HTML 并使用服务器端代码一遍又一遍地从数据库请求结果的需要。例如,运行 几个数据库查询,计算和处理 PHP 代码到 HTML 输出需要几秒钟,增加动态页面的整体页面加载时间,但缓存文件仅包含普通文件HTML 代码,您可以在任何文本编辑器或浏览器中打开它,这意味着它根本不需要处理时间。

动态页面:— 下图中的示例显示了如何生成动态页面。顾名思义,它是完全动态的,它与数据库对话并根据用户在请求期间提供的不同变量生成 HTML 输出。例如,用户可能想列出特定作者的所有书籍,它可以通过向数据库发送查询并生成新的 HTML 内容来实现,但每个请求都需要几秒钟的时间来处理,并且会占用一定的服务器内存,如果网站的访问者很少,这没什么大不了的。但是,考虑到成百上千的访问者一次又一次地从您的网站请求和生成动态页面,这将大大增加压力,导致客户端浏览器出现延迟输出和 HTTP 错误。

动态页面示例

缓存文件:— 下图说明了缓存文件是如何代替动态页面提供服务的,如上所述,缓存文件只不过是静态网页。它们包含纯 HTML 代码,缓存页面内容唯一会发生变化的方式是 Web 开发人员手动编辑文件。如您所见,缓存文件既不需要数据库连接也不需要处理时间,它是持续降低服务器压力和页面加载时间的理想解决方案。

缓存文件示例 PHP缓存

还有其他方法可以使用 PHP 来缓存动态页面,但大家最常使用的方法是 PHP Output Buffer 和 Filesystem Functions,结合这两种方法我们可以拥有宏伟的缓存系统.

PHP 输出缓冲区:——有趣的是,它提高了性能并减少了下载所需的时间,因为输出不是分段发送到浏览器,而是整个 HTML 页面一个变量。该方法非常简单,请看下面的代码:

<?php
ob_start(); // start the output buffer

/* the content */
ob_get_contents();  gets the contents of the output buffer
ob_end_flush(); // Send the output and turn off output buffering
?>

当您在代码顶部调用 ob_start() 时,它会打开输出缓冲,这意味着在此之后的任何内容都将存储在缓冲区中,而不是在浏览器上输出。可以使用 ob_get_contents() 检索缓冲区中的内容。您应该在代码末尾调用 ob_end_flush() 以将输出发送到浏览器并关闭缓冲。

PHP 文件系统:— 你可能对PHP文件系统很熟悉,它是PHP核心的一部分,允许我们读写文件系统。看看下面的代码。

$fp = fopen('/path/to/file.txt', 'w');  //open file for writing
fwrite($fp, 'I want to write this'); //write 
fclose($fp); //Close file pointer

如你所见,第一行代码fopen()打开文件进行写入,模式'w'将文件指针放在文件的开头,如果文件不存在,它会尝试创建一。第二行 fwrite() 将字符串写入打开的文件,最后 fclose() 在代码开头关闭成功打开的文件。 实施 PHP 缓存

现在你应该很清楚 PHP 输出缓冲区和文件系统了,我们可以使用这两种方法来创建我们的 PHP 缓存系统。请看下面的图片,流程图为我们提供了缓存系统的基本概念。

php-缓存系统

循环从用户请求内容开始,我们只检查当前请求页面的缓存副本是否存在,如果不存在则生成一个新页面,创建缓存副本然后输出结果。如果缓存已经存在,我们只需要获取文件并将其发送到用户浏览器即可。

查看下面的完整 PHP 缓存代码,您只需将其复制并粘贴到您的 PHP 项目中,它应该如上图所示完美运行。可以玩代码中的设置,修改缓存过期时间、缓存文件扩展名、忽略页面等

<?php
//settings
$cache_ext  = '.html'; //file extension
$cache_time     = 3600;  //Cache file expires afere these seconds (1 hour = 3600 sec)
$cache_folder   = 'cache/'; //folder to store Cache files
$ignore_pages   = array('', '');

$dynamic_url    = 'http://'.$_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . $_SERVER['QUERY_STRING']; // requested dynamic page (full url)
$cache_file     = $cache_folder.md5($dynamic_url).$cache_ext; // construct a cache file
$ignore = (in_array($dynamic_url,$ignore_pages))?true:false; //check if url is in ignore list

if (!$ignore && file_exists($cache_file) && time() - $cache_time < filemtime($cache_file)) { //check Cache exist and it's not expired.
ob_start('ob_gzhandler'); //Turn on output buffering, "ob_gzhandler" for the compressed page with gzip.
readfile($cache_file); //read Cache file
echo '<!-- cached page - '.date('l jS \of F Y h:i:s A', filemtime($cache_file)).', Page : '.$dynamic_url.' -->';
ob_end_flush(); //Flush and turn off output buffering
exit(); //no need to proceed further, exit the flow.
}
//Turn on output buffering with gzip compression.
ob_start('ob_gzhandler');
######## Your Website Content Starts Below #########
?>
<!DOCTYPE html>
<html>
<head>
<title>Page to Cache</title>
</head>
<body>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer ut tellus libero.
</body>
</html>
<?php
######## Your Website Content Ends here #########

if (!is_dir($cache_folder)) { //create a new folder if we need to
mkdir($cache_folder);
}
if(!$ignore){
$fp = fopen($cache_file, 'w');  //open file for writing
fwrite($fp, ob_get_contents()); //write contents of the output buffer in Cache file
fclose($fp); //Close file pointer
}
ob_end_flush(); //Flush and turn off output buffering

?>

您必须将 PHP 内容放在封闭的注释行之间,实际上我建议将它们放在单独的页眉和页脚文件中,以便它可以为所有不同的动态生成和提供缓存文件页。如果您仔细阅读代码中的注释行,您应该会发现它几乎是不言自明的。

您可以使用 cloudflare 在边缘执行此操作以获得更好的性能。好处是您可以随时将域设置为 "Under Development" 以查看代码更改 - 无需更改服务器端机制。

您的页面规则如下所示。请注意带有通配符的 url 变量。这意味着任何具有该变量名称的 url 都将缓存在边缘。您应该很容易看到 TTFB + 整个 html 下载不到 50 毫秒。

还要注意有效期。你说一个月所以我选择了那个设置。但我可能会将其设为“1 天”。就这样我可以随时关注事情。