Nginx - HTML 上没有最后修改时间或 Etag 响应标头

Nginx - HTML 上没有最后修改时间或 Etag 响应标头

我的 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 等)。

相关内容