我在运行 AlmaLinux 8 并安装了 Plesk 的服务器上有一个 Opencart 3.0.3.8 站点。服务器使用 PHP-FPM 和 Nginx。
我的网站大约有 7,000 个产品,使用完整的 SEO 包模块进行 SEO。单一产品页面和信息页面都有一个 .html 扩展名(这是一个非常古老的设置的遗留物,这个电子商务网站已有大约 15 年的历史)。 Varnish 对于格式为 https://www.example.com/single-product-page 的页面没有问题,但是当我在 https://www.example.com/single-product-page 上查看页面时.html,我看到 x-cache-status 绕过。我已经尝试了一切,但无法解决这个问题。有专家可以告诉我哪里可能出错吗?
标头输出如下:
content-encoding: gzip
content-type: text/html; charset=utf-8
date: Tue, 31 Dec 2024 13:26:58 GMT
permissions-policy: keyboard-map=(), attribution-reporting=(), run-ad-auction=(), private-state-token-redemption=(), private-state-token-issuance=(), join-ad-interest-group=(), idle-detection=(), compute-pressure=(), browsing-topics=()
server: nginx
vary: Accept-Encoding
x-cache-status: BYPASS
x-dns-prefetch-control: off
x-powered-by: PHP/7.3.33
x-powered-by: PleskLin
在 Plesk 面板中,为 http 定义了以下附加指令:
#PLESK-VARNISH-BEGIN
SetEnvIf X-Forwarded-Proto https HTTPS=on
Header set Vary "Accept-Encoding" env=!NO_VARY
<IfModule mod_rewrite.c>
RewriteEngine on
# We remove HTTPS redirection because we are behind Varnish
# RewriteCond %{HTTPS} !=on
# RewriteCond %{HTTP:X-Forwarded-Proto} !https [NC]
# RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
#PLESK-VARNISH-END
附加 nginx 指令部分定义如下:
#PLESK-VARNISH-BEGIN
location ~ ^/.* {
proxy_pass http://0.0.0.0:6081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
# Edit cookie and cache headers
proxy_hide_header Set-Cookie;
proxy_ignore_headers Set-Cookie;
proxy_set_header Cookie "";
# Timeout settings
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
}
#PLESK-VARNISH-END
这是default.vcl文件的内容:
#########################################################################
### The perfect Varnish 4.x+ configuration ###
### for WordPress, Joomla, Drupal & other (common) CMS based websites ###
#########################################################################
######################
#
# UPDATED on December 15th, 2021
#
# Configuration Notes:
# 1. Default dynamic content caching respects your backend's cache-control HTTP header.
# If however you need to enforce a different cache-control TTL,
# do a search for "180" and replace with the new value in seconds.
# Stale cache is served for up to 24 hours.
# 2. Make sure you update the "backend default { ... }" section with the correct IP and port
#
######################
# Varnish Reference:
# See the VCL chapters in the User-Guide at https://varnish-cache.org/docs/
# Marker to tell the VCL compiler that this VCL has been adapted to the new 4.1 format
vcl 4.1;
# Imports
import std;
# ACL defination
acl purge {
"localhost";
"127.0.0.1";
}
# Default backend definition. Set this to point to your content server.
backend default {
.host = "127.0.0.1";
.port = "7080";
}
sub vcl_recv {
std.log("Client IP: " + client.ip);
std.log("Request URL: " + req.url);
std.log("Request method: " + req.method);
# Cookie handling
if (req.http.Cookie) {
set req.http.Cookie = regsuball(req.http.Cookie, "^(OCSESSID=.*?;?).*$", "\1");
set req.http.Cookie = regsuball(req.http.Cookie, "^(language=.*?;?).*$", "\1");
set req.http.Cookie = regsuball(req.http.Cookie, "^(currency=.*?;?).*$", "\1");
if (req.http.Cookie ~ "^\s*$") {
unset req.http.Cookie;
}
}
# Basic request handling
if (req.http.Set-Cookie) { return(pass); }
# Purge handling
if (req.method == "PURGE") {
if (!client.ip ~ purge) {
return(synth(405, "Not allowed."));
}
if (req.http.X-Purge-Method == "regex") {
ban("req.url ~ " + req.http.X-Purge-Regex);
} else {
ban("req.url == " + req.url);
}
return(synth(200, "Cache cleared"));
}
# LetsEncrypt passthrough
if (req.url ~ "^/\.well-known/acme-challenge/") {
return (pass);
}
# Forward client IP
if (req.restarts == 0) {
if (req.http.X-Real-IP) {
set req.http.X-Forwarded-For = req.http.X-Real-IP;
} else if (req.http.X-Forwarded-For) {
set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
}
# Security
unset req.http.proxy;
# URL normalization
if (req.url !~ "wp-admin") {
set req.url = std.querysort(req.url);
}
# Method handling
if (req.method != "GET" && req.method != "HEAD" &&
req.method != "PUT" && req.method != "POST" &&
req.method != "TRACE" && req.method != "OPTIONS" &&
req.method != "DELETE") {
return (pipe);
}
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
}
# URL cleanup
if (req.url ~ "(\?|&)(_bta_[a-z]+|fbclid|gclid|utm_[a-z]+)=") {
set req.url = regsuball(req.url, "(_bta_[a-z]+|fbclid|gclid|utm_[a-z]+)=[-_A-z0-9+()%.]+&?", "");
set req.url = regsub(req.url, "[?|&]+$", "");
}
if (req.url ~ "\?$") { set req.url = regsub(req.url, "\?$", ""); }
if (req.url ~ "\#") { set req.url = regsub(req.url, "\#.*$", ""); }
# Cookie cleanup
std.collect(req.http.Cookie);
set req.http.Cookie = regsuball(req.http.Cookie, "(has_js|_ga|wp-settings-[0-9]+|wordpress_test_cookie)=[^;]+(; )?", "");
set req.http.Cookie = regsuball(req.http.Cookie, "^;\s*", "");
if (req.http.cookie ~ "^\s*$") { unset req.http.cookie; }
# Cache bypass conditions
if (req.http.Authorization ||
req.http.Authenticate ||
req.http.X-Logged-In == "True" ||
req.http.Cookie ~ "(userID|joomla_[a-zA-Z0-9_]+|wordpress_[a-zA-Z0-9_]+|wp-postpass)") {
return (pass);
}
# Path exclusions
if (req.url ~ "^/(administrator|cart|checkout|login|wp-admin|wp-login.php)") {
return (pass);
}
# AJAX handling
if (req.http.X-Requested-With == "XMLHttpRequest" || req.url ~ "nocache") {
return (pass);
}
# Static file handling
if (req.http.Accept-Encoding) {
if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
unset req.http.Accept-Encoding;
} elsif (req.http.Accept-Encoding ~ "gzip") {
set req.http.Accept-Encoding = "gzip";
} elsif (req.http.Accept-Encoding ~ "deflate") {
set req.http.Accept-Encoding = "deflate";
} else {
unset req.http.Accept-Encoding;
}
}
# Static content bypass
if (req.url ~ "\.(css|js|jpg|jpeg|png|gif|ico|woff|ttf|eot|svg)$") {
unset req.http.Cookie;
return (hash);
}
return (hash);
}
sub vcl_backend_response {
# Static file optimization
if (bereq.url ~ "\.(jpg|jpeg|gif|png|css|js|ico|woff|ttf|eot|svg)$") {
unset beresp.http.Set-Cookie;
set beresp.ttl = 30d;
set beresp.http.Cache-Control = "public, max-age=2592000";
}
# Error handling
if (beresp.status >= 500 && beresp.status <= 504) {
return (abandon);
}
# Cache control
if (beresp.http.Cache-Control !~ "max-age" || beresp.http.Cache-Control ~ "max-age=0") {
set beresp.http.Cache-Control = "public, max-age=180, stale-while-revalidate=360, stale-if-error=43200";
}
# Header cleanup
unset beresp.http.Pragma;
unset beresp.http.Vary;
set beresp.grace = 24h;
return (deliver);
}
sub vcl_deliver {
# Cache status headers
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT";
set resp.http.X-Cache-Hits = obj.hits;
std.log("Cache HIT for: " + req.url);
} else {
set resp.http.X-Cache = "MISS";
std.log("Cache MISS for: " + req.url);
}
return (deliver);
}
日志可能会公开有关页面未缓存原因的更多信息。
假设我们正在调试假设的
/single-product-page.html
产品页面,日志记录命令如下:
sudo varnishlog -g request -q "ReqUrl eq '/single-product-page.html'"
请将此
varnishlog
命令的完整输出粘贴到您的原始问题中。输出可以包含多个相关交易(请求交易和后端请求交易)。
我将帮助您分析输出并弄清楚发生了什么。请确保在
varnishlog
运行时触发该页面。另请调整过滤模式,以确保 /single-product-page.html
替换为实际产品页面。