Laravel 结合 Nginx 实现 Web 页面的纯静态极限访问性能
最新在用 Laravel 做一个博客信息聚合的小项目,考虑到内容的更新频率和目前项目的价值,思考了下怎么尽最大可能节省服务器计算资源,最好是能够第一次访问时生成内容后,在内容没有变化时,直接以纯静态的方式直接输出,完全不要有 PHP-FPM 的参与。在经过一番尝试后,结合 Nginx 终于实现了这个想法。
整个逻辑不复杂,但在 Nginx 配合的这一层花了些时间,主要还是对 Nginx 的配置了解的不够深入。核心流程就两步:
- 实现一个新的 Laravel 视图加载处理方法。即在默认的
view
方法基础上,添加输出前的渲染结果保存逻辑。 - 使 Nginx 优先读取缓存的渲染内容,如果没有渲染时再执行 Laravel 的处理逻辑。
下面分别针对这两步做一个详细的说明。
首先是第一步的保存视图渲染内容,我写了一个全局函数,主要代码如下:
<?php
use Storage;
if (! function_exists('staticize_view')) {
function staticize_view($view = null, $data = [], $mergeData = [])
{
$viewObject = view($view, $data, $mergeData);
$filename = request()->path();
if (substr($filename, -1) != '/') {
$filename .= '.html';
}
if (substr($filename, -5) != '.html') {
$filename .= 'index.html';
}
if (substr($filename, 0, 1) != '/') {
$filename = '/'.$filename;
}
Storage::disk('local')->put('staticize_view'.$filename, $viewObject->render());
return $viewObject;
}
}
然后根据需要,再需要实现静态化访问的控制器方法中替换 view
函数为 staticize_view
就可以了。生成的渲染内容文件以 .html
后缀的形式保存在项目的 storage/app/staticize_view/ 目录下。
接下来就是最重要的第二步,实现 Nginx 默认优先输出静态缓存内容的行为。这一步需要利用 Nginx 的 try_files
指令。核心配置如下:
location / {
root /Projects/zzxworld/storage/app/staticize_view;
index index.html;
try_files $uri $uri/ $uri.html @default;
}
location @default {
root /Projects/zzxworld/public;
index index.php;
try_files $uri $uri/ /index.php?$query_string;
}
try_files
是基于 root
来查找目录的,所以需要利用两个 location
分别来实现先静态目录查找,然后再引导到 PHP 处理的流程。我开始不了解 try_files
的特性,一直想用一个 location
和 try_files
来实现,浪费了一些时间。