zzxworld

Apache 服务状态页面是如何自动刷新的

知乎上看到一个提问,内容是 Apache 服务状态页面在不加刷新代码的前提下如何实现自动刷新。我虽然不用 Apache,但对这个问题还是比较好奇,所以专门探究了一下,本文是过程记录。

安装 Apache

自从多年前体验到 Nginx 的性能后,就一直没再用过 Apache。为了还原出 Apache 状态页自动刷新的场景,我需要先安装 Apache。有了 Docker,这是小事一桩。直接启动一个 Apache 容器即可:

podman run --rm -it -p 8080:80 --name apache httpd

忘了说了,我目前主要使用 Podman 这个容器引擎,所以上面的命令是 podman。这个用起来和 Docker 差不多,不用在意这方面的差异,把上面命令中的 podman 换成 docker 一样能执行。

命令执行后等待镜像拉取,稍侯容器启动完成。然后从运行的 Apache 容器中复制一份配置文件出来:

podman cp apache:/usr/local/apache2/conf/httpd.conf ./

在复制出来的配置文件中添加以下配置,启用状态统计功能:

<Location "/server-status">
    SetHandler server-status
</Location>

然后按 Ctrl + C 键关闭运行的 Apache 容器,使用下面的命令以加载自定义配置的方式再次启动容器:

podman run --rm -it \
    -v $PWD/httpd.conf:/usr/local/apache2/conf/httpd.conf \
    -p 8080:80 --name apache httpd

打开浏览器,输入 http://localhost:8080/server-status,就可以看到 Apache 的状态统计页面。

Apache Status

在访问地址后加入 ?refresh=3,会发现这个页面真的每隔 3 秒就会自动刷新一次。那么,它是如何实现的?

自动刷新的方法

我所知道的浏览器自动刷新主要有两类。第一类是比较常见的前端方式。也就是在 HTML 代码来实现。比如添加一个 <meta> 元标签:

<meta http-equiv="refresh" content="3" />

这样就能实现每 3 秒刷新一次当前页面的功能。

或是通过 Javascript 代码:

setTimeout(() => {
    document.location.reload();
}, 3000);

这同样也能实现每 3 秒刷新一次当前页面的功能。不过 Apache 这个页面的内容就像文章开头所说的那样,页面中没有任何类似的自动刷新代码。所以我想是不是使用了第二类自动刷新的方案:即使用后端的方式。

后端方式刷型通常会采用长连接,这样可以更加实时的实现一些数据自动更新功能。不过这通常也离不开在前端使用 JavaScript 来响应并处理这些长连接。但在这个 Apache 的状态页面,我没有看到任何 JavaScript 代码。所以我只能把目光定在了 HTTP 响应协议上。

下图是 Apache 状态页面自动刷新下的响应头。

Refresh 响应头

一眼就能发现其中有一个 Refresh,后面的 30 是我为了方便截图,把刷新值调大了。所以谜底解开了,Apache 的这个自动刷新页面的功能就是通过 Refresh 响应头来实现的。