我的 Web 服务器遇到了一个相当奇怪的问题。该服务器配置了 Ubuntu 20.04、Nginx v1.22.1、PHP 8.0 和 MariaDB 来托管我的 WordPress 网站。
问题是,服务器没有发送任何 HTML 页面的 Etag 或最后修改响应标头,导致浏览器始终获得响应200 OK
,而永远不会304 Not Modified
。我已经使用该模块配置了浏览器缓存ngx_http_headers_module
。
奇怪的是,Etags 和 last-modified 标头以及缓存控制标头在所有静态资产(包括 JS、CSS 和图像)上都运行正常。但 HTML 却不行。
以下是我的主要配置文件,供参考:
user jay;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 1024;
multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
keepalive_timeout 60;
tcp_nopush on;
types_hash_max_size 2048;
server_tokens off;
client_max_body_size 64M;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
# gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
##
# Security
##
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains" always;
add_header X-Xss-Protection "1; mode=block" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444;
}
}
以下是我的站点级配置:
# Expires map
map $sent_http_content_type $expires {
default off;
text/html epoch;
text/css max;
application/javascript max;
~image/ max;
~font/ max;
}
server {
listen 443 ssl http2;
server_name www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
access_log /home/jay/example.com/logs/access.log;
error_log /home/jay/example.com/logs/error.log;
expires $expires;
root /home/jay/example.com/public/;
index index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php8.0-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
}
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
return 301 https://www.example.com$request_uri;
}
server {
listen 80;
server_name example.com www.example.com;
return 301 https://www.example.com$request_uri;
}
我目前所做的:
- 通过完全删除 CloudFlare,消除了其干扰响应的可能性。
- 删除了所有 WordPress 插件和主题。已移至默认主题。
- 使用相同的配置重新设置新的 VPS。
但一切都是徒劳。
有人能帮忙吗?这可能是什么原因造成的?
编辑:
以下是 HTML 上 curl 的输出:
HTTP/2 200
server: nginx
date: Thu, 05 Jan 2023 14:59:14 GMT
content-type: text/html; charset=UTF-8
link: <https://www.example.com/wp-json/>; rel="https://api.w.org/"
x-fastcgi-cache: HIT
strict-transport-security: max-age=31536000; includeSubdomains
x-xss-protection: 1; mode=block
x-frame-options: SAMEORIGIN
x-content-type-options: nosniff
referrer-policy: strict-origin-when-cross-origin
即使重复卷曲,输出仍保持不变。
以下是静态文件(例如网站的 CSS)的输出:
HTTP/2 200
server: nginx
date: Thu, 05 Jan 2023 15:01:50 GMT
content-type: text/css
content-length: 22256
last-modified: Wed, 04 Jan 2023 16:37:20 GMT
etag: "63b5ab40-56f0"
expires: Thu, 31 Dec 2037 23:55:55 GMT
cache-control: max-age=315360000
strict-transport-security: max-age=31536000; includeSubdomains
x-xss-protection: 1; mode=block
x-frame-options: SAMEORIGIN
x-content-type-options: nosniff
referrer-policy: strict-origin-when-cross-origin
accept-ranges: bytes
答案1
欢迎来到 ServerFault。
按照https://nginx.org/r/etag,etag 只能为静态内容启用。不能用于动态 HTML 内容。我相信类似的方法也适用于“上次修改”标头。无论如何,如果您的目标是添加 expires 标头,那么还有其他方法可以实现这一点,例如使用全页面缓存插件,其中为每个帖子/页面生成静态 HTML。Nginx 分阶段进行配置,expires 可能仅适用于静态资源。不过,我可能错了。可能需要使用调试来了解何时将 expires 应用于请求。
您是否知道是否可以在 FastCGI 缓存的 HTML 文档上添加这些相同的响应标头?
不可以。没有办法为 FastCGI 缓存的内容配置“etag”或“last-modified”标头。
如果您的目的只是配置“expires”,那么您可以expires
在 php 位置块中使用如下所示的内容...
location ~* \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) { return 404; }
# Mitigate https://httpoxy.org/ vulnerabilities
fastcgi_param HTTP_PROXY "";
include "fastcgi_params";
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
fastcgi_pass fpm;
fastcgi_cache PHP_CACHE;
fastcgi_cache_valid 200 10m;
expires 10m;
add_header "Cache-Control" "must-revalidate";
add_header X-Cache $upstream_cache_status;
}
此处,“expires”与 FastCGI Cache 无关。因此,上述代码将向cache-control: max-age=600
所有 PHP 请求发送标头,包括example.com/wp-login.php
(即使 FastCGI Cache 不会缓存它)。因此,您可以在不同的位置块中配置此类 URL(/wp-admin/、/wp-comment-post.php 等)。