我正在做一个涉及 PHP 内置网络服务器的测试项目,我正在测试一些想法。
我想对常用资源(png、jpg、json、txt等)实现自己的缓存机制,以减少php内置服务器的负载。
我这样启动内置服务器:
php -S 127.0.0.1:80 -t public router.php
因此,内置服务器的文档根目录设置为 public
并运行 router.php
(因为我正在考虑实现一个简单的重写功能也)。
这是我的 router.php
文件的内容:
<?php
// Register request uri
$requestUri = isset($_SERVER['REQUEST_URI'])
? $_SERVER['REQUEST_URI']
: '/';
// Handle app resources with caching
if (preg_match('/\.(?:png|jpg|jpeg|gif|xml|json|css|eot|svg|otf|ttf|woff|woff2|scss|less|txt|ico)$/', $requestUri))
{
// Generate file name
$fileName = __DIR__ .'/public'. $requestUri;
// Parse file data
$lastModified = filemtime($fileName);
$etagFile = md5_file($fileName);
$ifModifiedSince = (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : false);
$etagHeader = (isset($_SERVER['HTTP_IF_NONE_MATCH']) ? trim($_SERVER['HTTP_IF_NONE_MATCH']) : false);
// Set caching header
header('Last-Modified: '. gmdate('D, d M Y H:i:s', $lastModified) .' GMT');
header('Etag: '. $etagFile);
header('Cache-Control: public');
// Check if the requested resource has changed
if (@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $lastModified || $etagHeader == $etagFile)
{
// File has not changed
header('HTTP/1.1 304 Not Modified');
exit;
}
else
{
// Parse requested resource's mime type
$finfo = new finfo(FILEINFO_MIME);
$mime_type = $finfo->buffer(
file_get_contents($fileName, false, null, -1, 64),
FILEINFO_MIME_TYPE
);
// Serve requested resource
header('Content-Type: '. $mime_type);
header('Content-Length: '. filesize($fileName));
@readfile($fileName);
$finfo = null;
exit;
}
}
// Parse requested page & action
list ($page, $action) =
array_pad(array_values(array_filter(explode('/', $requestUri, 3), 'strlen')), 2, 'index');
if ($page == 'index') $page = 'server';
// Test - to do rest of routing
var_dump('page = '. $page);
var_dump('action = '. $action);
// include 'app/'. $page .'/'. $action .'.php';
?>
我通过访问以下网址测试了资源(png 图像)缓存:http://localhost/apple-icon-120x120.png
因此,这是资源的第一次加载,因此服务按预期返回具有 HTTP 200
响应的资源,大约需要 307ms
:
现在,如果我按 F5
重新加载页面,服务器将按预期返回 HTTP 304
(未修改)并且请求花费了大约 5ms
(太棒了!!):
如果我第三次按F5
,服务器仍然按预期返回HTTP 304
(未修改),但是这次请求花费了大约306ms
再次(好像资源没有被缓存):
如果我一直按 F5
,处理请求的时间将在 5m
和大约 307ms
之间随机交替。
知道为什么会这样吗?一旦资源被缓存,它不应该不断返回 304
并处理大约 5ms
的请求吗?为什么行为是零星的?
我确实看到返回的内容大小是 225 字节
(当它知道数据被缓存时),我只是无法弄清楚请求处理时间的瓶颈在哪里。我的主机运行的是带有 Intel i7 CPU、6GB RAM 和 SSD 驱动器的 Windows。
最佳答案
您的路由器文件工作正常。我已经在本地对其进行了测试,它的行为符合预期:第一次是带下载的 HTTP 200,然后是只有 header 的 HTTP 304。
查看您的时间轴,需要 307 毫秒才能响应 11.9 KB,这显然太慢了。
您确实收到了 HTTP 304,因此您的脚本一定是在未发送文件的情况下退出的。但是,要在第一个实例中发送 304 状态代码,PHP 仍然必须找到 mtime
并计算文件的 md5
哈希。访问文件可能是瓶颈。
响应时间在 5 毫秒和 300 毫秒之间交替可能是由磁盘缓存引起的。也许您有硬盘驱动器或混合驱动器?
为什么不在开始时、mtime
之前和哈希计算之后回显 microtime()
?
关于php内置网络服务器缓存问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33149339/