如何在 Wordpress 中创建动态页面而不遇到缓存问题?
How do you create a dynamic page in Wordpress and not encounter issues with caching?
我是 运行 一个带有 Wordpress 博客的 RoR 网站,我刚刚在 Wordpress 中使用主 (RoR) 站点设置的 cookie 实现了登录/注销 header用户登录。
一切正常,除了当用户登录或注销(从 RoR 站点)时,我需要在 wordpress 站点上进行硬刷新才能看到修改后的 header。我需要解决这个问题。
我的问题是 - 这是我的缓存设置的问题,还是我应该以不同的方式实施解决方案?
我的解决方案
我的 RoR 网站会在用户登录时创建一个名为 'login' 的 cookie,并在用户注销时删除该 cookie。
我编辑了 child 主题的 header.php
以插入此代码:
<?php if(isset($_COOKIE['login'])) : ?>
<!-- logged in header -->
<?php else : ?>
<!-- not logged in header -->
<?php endif; ?>
缓存
我正在使用很多 caching/optimisation plugins/services/settings 包括:
- Cloudflare
- WP 超级缓存
- 自动优化
- Apache 配置设置 Cache-Control 和过期标题
首先,我禁用了 WP Super Cache,因为它的主要功能似乎是缓存 HTML 和 PHP,并且在插件处于活动状态的情况下,我需要在 [=79= 之前删除缓存] 将通过硬刷新进行更新。
然后我取消选中 Autoptimze 设置以禁用 HTML 的缓存。
然后我检查了我的 Cloudflare 设置 - 我正在使用标准缓存,使用现有的 headers,并且没有进行任何缩小。
最后我的 Apache 配置似乎是正确的:
<IfModule mod_headers.c>
...
<FilesMatch "\.(html|htm|php|pdf)$">
Header set Cache-Control "max-age=0, private, no-store, no-cache, must-revalidate"
</FilesMatch>
</IfModule>
作为附加测试,我直接(通过 IP 地址)访问了该网站,这似乎工作正常。我还 运行 在 Chrome 开发人员工具的“网络”选项卡上勾选了 "disable cache" 的一些测试,效果也很好。
因此我认为现在问题出在 Chrome 上。
当我查看 HTTP 请求 headers 时,在注销或登录后返回到 Wordpress 站点后,我看到了这个:
Status Code: 200 (from disk cache)
当我点击浏览器刷新按钮时,页面刷新并且 header 是正确的。
这是显示不正确 header 时的 HTTP 响应 header:
cache-control: private, must-revalidate
cf-cache-status: DYNAMIC
cf-ray: 593e0b2e0cc706c5-LHR
cf-request-id: 02baa550c6000006c5e7912200000001
content-encoding: br
content-type: text/html; charset=UTF-8
date: Fri, 15 May 2020 15:55:31 GMT
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
expires: Fri, 15 May 2020 16:05:30 GMT
link: <https://www.example.com/blog/wp-json/>; rel="https://api.w.org/"
server: cloudflare
status: 200
vary: Accept-Encoding,User-Agent
这是我按下浏览器刷新按钮时的 HTTP 响应 header:
Request URL: https://www.example.com/blog/
Request Method: GET
Status Code: 200
Remote Address: 104.27.165.96:443
Referrer Policy: no-referrer-when-downgrade
cache-control: private, must-revalidate
cf-cache-status: DYNAMIC
cf-ray: 593e10d669ca06c5-LHR
cf-request-id: 02baa8da04000006c5e7896200000001
content-encoding: br
content-type: text/html; charset=UTF-8
date: Fri, 15 May 2020 15:59:22 GMT
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
expires: Fri, 15 May 2020 16:09:22 GMT
link: <https://www.example.com/blog/wp-json/>; rel="https://api.w.org/"
server: cloudflare
status: 200
vary: Accept-Encoding,User-Agent
:authority: www.example.com
:method: GET
:path: /blog/
:scheme: https
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
accept-encoding: gzip, deflate, br
accept-language: en-ZA,en-GB;q=0.9,en-US;q=0.8,en;q=0.7,fr;q=0.6
cache-control: max-age=0
cookie: wordpress_test_cookie=WP%20Cookie%20check; __cfduid=dc19950d1c3d6d8e54fefd2b87c81a1e71589464189; _ga=GA1.2.1235735685.1589464190; _gid=GA1.2.1339832334.1589464190; _hjid=3f0fe3a6-cb06-4d37-886f-0358763f067e; _omappvp=Mhy6L4AKmb5TVpPhcNdtRDjwoZyTAfz7srbL1nfNUhhH7T6zyUjp3DYhWoOTp3vaiLL7tFM8xPRzCSb3KKuxM0xkiNhsOfS1; _fbp=fb.1.1589464195337.1508307578; intercom-id-qe94ii0z=b3b88868-e461-4624-a6aa-9c4b0ef77e76; _hjIncludedInSample=1; om-700710=true; editing=viewed; _gaexp=GAX1.2.R8_xwTncQfCHf-7lseMIpQ.18441.1!I2ThxUMmSpOQ2bSwIUXW-g.18445.0; _hjAbsoluteSessionInProgress=1; intercom-session-qe94ii0z=S1dLWUcvTUdEdldSeEJXOEdJOURZVW02cDBkdWROZ2tEMWZPekZxV2llSTJRSTlxQVNhVW5BODdCMUFuK2NwSC0tM1o2QTdDbHFxMklja0l4TTFpOXlMZz09--29bdb35de1443e4d7dbe4c5f56289131b74e2b36; _gat=1; _example_session=BAh7CUkiD3Nlc3Npb25faWQGOgZFVEkiJWJkYmJlMTM4NmE3ODg0YmY5ZjdlYTZjM2E2Y2M1ZWY4BjsAVEkiCmZsYXNoBjsAVHsHSSIMZGlzY2FyZAY7AFRbBkkiCmFsZXJ0BjsARkkiDGZsYXNoZXMGOwBUewZADEkiNllvdSBuZWVkIHRvIHNpZ24gaW4gb3Igc2lnbiB1cCBiZWZvcmUgY29udGludWluZy4GOwBUSSIQX2NzcmZfdG9rZW4GOwBGSSIxU2tRY1N6LzFSMGx2RGFlQ1BNMzgzZHBCQ1FIL3AxK2prd0NobmZaZ1Z1dz0GOwBGSSITdXNlcl9yZXR1cm5fdG8GOwBUIhUvZGFzaGJvYXJkL2luZGV4--242e9a815510fe910d3372b5b9e2ef8bc8f800e4
referer: https://www.example.com/users/sign_in
sec-fetch-dest: document
sec-fetch-mode: navigate
sec-fetch-site: same-origin
sec-fetch-user: ?1
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36
我终于能够在服务器上使用 wget
调试此问题,如下所示:
$ wget https://localhost/blog/ --no-check-certificate --server-response
一旦我禁用了我在 Wordpress 中用于缓存的两个插件,这个命令允许我绕过 Cloudflare 并查看 Apache 设置的 headers。
--2020-05-19 13:21:08-- https://localhost/blog/
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:443... connected.
WARNING: cannot verify localhost's certificate, issued by ‘ST=California,L=San Francisco,OU=CloudFlare Origin SSL Certificate Authority,O=CloudFlare\, Inc.,C=US’:
Unable to locally verify the issuer's authority.
WARNING: no certificate subject alternative name matches
requested host name ‘localhost’.
HTTP request sent, awaiting response...
HTTP/1.1 200 OK
Date: Tue, 19 May 2020 12:21:08 GMT
Server: Apache
Link: <https://localhost/blog/wp-json/>; rel="https://api.w.org/"
Cache-Control: private, must-revalidate
Expires: Tue, 19 May 2020 12:31:08 GMT
Vary: Accept-Encoding,User-Agent
Content-Type: text/html; charset=UTF-8
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Length: unspecified [text/html]
Saving to: ‘index.html’
我注意到 Cache-Control header 与我的 Apache 配置中的不同。
Cache-Control: max-age=0, private, no-store, no-cache, must-revalidate
这是因为 Cache-Control header 是在根域 Apache 配置中设置的,而不是为博客设置的(它由反向代理托管)。
解决方案是将所有 Expires 和 Cache-Control header 配置复制到我的博客 Apache 配置文件中,然后瞧瞧:
$ wget https://localhost/blog/ --no-check-certificate --server-response--2020-05-19 16:41:19-- https://localhost/blog/
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:443... connected.
WARNING: cannot verify localhost's certificate, issued by ‘ST=California,L=San Francisco,OU=CloudFlare Origin SSL Certificate Authority,O=CloudFlare\, Inc.,C=US’:
Unable to locally verify the issuer's authority.
WARNING: no certificate subject alternative name matches
requested host name ‘localhost’.
HTTP request sent, awaiting response...
HTTP/1.1 200 OK
Date: Tue, 19 May 2020 15:41:20 GMT
Server: Apache
Vary: Accept-Encoding,Cookie,User-Agent
Link: <https://localhost/blog/wp-json/>; rel="https://api.w.org/"
Cache-Control: private, no-store, no-cache, must-revalidate
Expires: Tue, 19 May 2020 15:41:20 GMT
Content-Type: text/html; charset=UTF-8
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Length: unspecified [text/html]
Saving to: ‘index.html’
为了完整起见,请参阅我的博客的新 Apache 配置:
# avoids sending hackers too much info about the server
ServerTokens Prod
<VirtualHost *:8080>
ServerName www.example.com
ServerAdmin dagmar@example.com
ErrorLog /var/log/apache2/blog/error.log
CustomLog /var/log/apache2/blog/access.log common
DocumentRoot /var/www/blog
<Directory /var/www/blog>
AllowOverride All
Options -Indexes
</Directory>
# Enable Compression
<IfModule mod_deflate.c>
SetOutputFilter DEFLATE
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI \.(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary
Header append Vary User-Agent
</IfModule>
# Enable expires headers
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/pdf "access plus 1 month"
ExpiresByType text/x-javascript "access plus 1 month"
ExpiresByType text/javascript "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType application/x-javascript "access plus 1 month"
ExpiresByType image/x-icon "access plus 1 year"
ExpiresByType text/xml "access plus 0 seconds"
ExpiresByType text/html "access plus 0 seconds"
ExpiresByType text/plain "access plus 0 seconds"
ExpiresByType application/xml "access plus 0 seconds"
ExpiresByType application/json "access plus 0 seconds"
ExpiresByType application/rss+xml "access plus 1 hour"
ExpiresByType application/atom+xml "access plus 1 hour"
ExpiresByType text/x-component "access plus 1 hour"
ExpiresDefault "access plus 0 seconds"
</IfModule>
# Enable caching headers
<IfModule mod_headers.c>
# Calculate etag on modified time and file size (could be turned off too ?)
FileETag MTime Size
# NEVER CACHE - notice the extra directives
<FilesMatch "\.(html|htm|php)$">
Header set Cache-Control "private, no-store, no-cache, must-revalidate"
</FilesMatch>
</IfModule>
我是 运行 一个带有 Wordpress 博客的 RoR 网站,我刚刚在 Wordpress 中使用主 (RoR) 站点设置的 cookie 实现了登录/注销 header用户登录。
一切正常,除了当用户登录或注销(从 RoR 站点)时,我需要在 wordpress 站点上进行硬刷新才能看到修改后的 header。我需要解决这个问题。
我的问题是 - 这是我的缓存设置的问题,还是我应该以不同的方式实施解决方案?
我的解决方案
我的 RoR 网站会在用户登录时创建一个名为 'login' 的 cookie,并在用户注销时删除该 cookie。
我编辑了 child 主题的 header.php
以插入此代码:
<?php if(isset($_COOKIE['login'])) : ?>
<!-- logged in header -->
<?php else : ?>
<!-- not logged in header -->
<?php endif; ?>
缓存
我正在使用很多 caching/optimisation plugins/services/settings 包括:
- Cloudflare
- WP 超级缓存
- 自动优化
- Apache 配置设置 Cache-Control 和过期标题
首先,我禁用了 WP Super Cache,因为它的主要功能似乎是缓存 HTML 和 PHP,并且在插件处于活动状态的情况下,我需要在 [=79= 之前删除缓存] 将通过硬刷新进行更新。
然后我取消选中 Autoptimze 设置以禁用 HTML 的缓存。
然后我检查了我的 Cloudflare 设置 - 我正在使用标准缓存,使用现有的 headers,并且没有进行任何缩小。
最后我的 Apache 配置似乎是正确的:
<IfModule mod_headers.c>
...
<FilesMatch "\.(html|htm|php|pdf)$">
Header set Cache-Control "max-age=0, private, no-store, no-cache, must-revalidate"
</FilesMatch>
</IfModule>
作为附加测试,我直接(通过 IP 地址)访问了该网站,这似乎工作正常。我还 运行 在 Chrome 开发人员工具的“网络”选项卡上勾选了 "disable cache" 的一些测试,效果也很好。
因此我认为现在问题出在 Chrome 上。
当我查看 HTTP 请求 headers 时,在注销或登录后返回到 Wordpress 站点后,我看到了这个:
Status Code: 200 (from disk cache)
当我点击浏览器刷新按钮时,页面刷新并且 header 是正确的。
这是显示不正确 header 时的 HTTP 响应 header:
cache-control: private, must-revalidate
cf-cache-status: DYNAMIC
cf-ray: 593e0b2e0cc706c5-LHR
cf-request-id: 02baa550c6000006c5e7912200000001
content-encoding: br
content-type: text/html; charset=UTF-8
date: Fri, 15 May 2020 15:55:31 GMT
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
expires: Fri, 15 May 2020 16:05:30 GMT
link: <https://www.example.com/blog/wp-json/>; rel="https://api.w.org/"
server: cloudflare
status: 200
vary: Accept-Encoding,User-Agent
这是我按下浏览器刷新按钮时的 HTTP 响应 header:
Request URL: https://www.example.com/blog/
Request Method: GET
Status Code: 200
Remote Address: 104.27.165.96:443
Referrer Policy: no-referrer-when-downgrade
cache-control: private, must-revalidate
cf-cache-status: DYNAMIC
cf-ray: 593e10d669ca06c5-LHR
cf-request-id: 02baa8da04000006c5e7896200000001
content-encoding: br
content-type: text/html; charset=UTF-8
date: Fri, 15 May 2020 15:59:22 GMT
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
expires: Fri, 15 May 2020 16:09:22 GMT
link: <https://www.example.com/blog/wp-json/>; rel="https://api.w.org/"
server: cloudflare
status: 200
vary: Accept-Encoding,User-Agent
:authority: www.example.com
:method: GET
:path: /blog/
:scheme: https
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
accept-encoding: gzip, deflate, br
accept-language: en-ZA,en-GB;q=0.9,en-US;q=0.8,en;q=0.7,fr;q=0.6
cache-control: max-age=0
cookie: wordpress_test_cookie=WP%20Cookie%20check; __cfduid=dc19950d1c3d6d8e54fefd2b87c81a1e71589464189; _ga=GA1.2.1235735685.1589464190; _gid=GA1.2.1339832334.1589464190; _hjid=3f0fe3a6-cb06-4d37-886f-0358763f067e; _omappvp=Mhy6L4AKmb5TVpPhcNdtRDjwoZyTAfz7srbL1nfNUhhH7T6zyUjp3DYhWoOTp3vaiLL7tFM8xPRzCSb3KKuxM0xkiNhsOfS1; _fbp=fb.1.1589464195337.1508307578; intercom-id-qe94ii0z=b3b88868-e461-4624-a6aa-9c4b0ef77e76; _hjIncludedInSample=1; om-700710=true; editing=viewed; _gaexp=GAX1.2.R8_xwTncQfCHf-7lseMIpQ.18441.1!I2ThxUMmSpOQ2bSwIUXW-g.18445.0; _hjAbsoluteSessionInProgress=1; intercom-session-qe94ii0z=S1dLWUcvTUdEdldSeEJXOEdJOURZVW02cDBkdWROZ2tEMWZPekZxV2llSTJRSTlxQVNhVW5BODdCMUFuK2NwSC0tM1o2QTdDbHFxMklja0l4TTFpOXlMZz09--29bdb35de1443e4d7dbe4c5f56289131b74e2b36; _gat=1; _example_session=BAh7CUkiD3Nlc3Npb25faWQGOgZFVEkiJWJkYmJlMTM4NmE3ODg0YmY5ZjdlYTZjM2E2Y2M1ZWY4BjsAVEkiCmZsYXNoBjsAVHsHSSIMZGlzY2FyZAY7AFRbBkkiCmFsZXJ0BjsARkkiDGZsYXNoZXMGOwBUewZADEkiNllvdSBuZWVkIHRvIHNpZ24gaW4gb3Igc2lnbiB1cCBiZWZvcmUgY29udGludWluZy4GOwBUSSIQX2NzcmZfdG9rZW4GOwBGSSIxU2tRY1N6LzFSMGx2RGFlQ1BNMzgzZHBCQ1FIL3AxK2prd0NobmZaZ1Z1dz0GOwBGSSITdXNlcl9yZXR1cm5fdG8GOwBUIhUvZGFzaGJvYXJkL2luZGV4--242e9a815510fe910d3372b5b9e2ef8bc8f800e4
referer: https://www.example.com/users/sign_in
sec-fetch-dest: document
sec-fetch-mode: navigate
sec-fetch-site: same-origin
sec-fetch-user: ?1
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36
我终于能够在服务器上使用 wget
调试此问题,如下所示:
$ wget https://localhost/blog/ --no-check-certificate --server-response
一旦我禁用了我在 Wordpress 中用于缓存的两个插件,这个命令允许我绕过 Cloudflare 并查看 Apache 设置的 headers。
--2020-05-19 13:21:08-- https://localhost/blog/
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:443... connected.
WARNING: cannot verify localhost's certificate, issued by ‘ST=California,L=San Francisco,OU=CloudFlare Origin SSL Certificate Authority,O=CloudFlare\, Inc.,C=US’:
Unable to locally verify the issuer's authority.
WARNING: no certificate subject alternative name matches
requested host name ‘localhost’.
HTTP request sent, awaiting response...
HTTP/1.1 200 OK
Date: Tue, 19 May 2020 12:21:08 GMT
Server: Apache
Link: <https://localhost/blog/wp-json/>; rel="https://api.w.org/"
Cache-Control: private, must-revalidate
Expires: Tue, 19 May 2020 12:31:08 GMT
Vary: Accept-Encoding,User-Agent
Content-Type: text/html; charset=UTF-8
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Length: unspecified [text/html]
Saving to: ‘index.html’
我注意到 Cache-Control header 与我的 Apache 配置中的不同。
Cache-Control: max-age=0, private, no-store, no-cache, must-revalidate
这是因为 Cache-Control header 是在根域 Apache 配置中设置的,而不是为博客设置的(它由反向代理托管)。
解决方案是将所有 Expires 和 Cache-Control header 配置复制到我的博客 Apache 配置文件中,然后瞧瞧:
$ wget https://localhost/blog/ --no-check-certificate --server-response--2020-05-19 16:41:19-- https://localhost/blog/
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:443... connected.
WARNING: cannot verify localhost's certificate, issued by ‘ST=California,L=San Francisco,OU=CloudFlare Origin SSL Certificate Authority,O=CloudFlare\, Inc.,C=US’:
Unable to locally verify the issuer's authority.
WARNING: no certificate subject alternative name matches
requested host name ‘localhost’.
HTTP request sent, awaiting response...
HTTP/1.1 200 OK
Date: Tue, 19 May 2020 15:41:20 GMT
Server: Apache
Vary: Accept-Encoding,Cookie,User-Agent
Link: <https://localhost/blog/wp-json/>; rel="https://api.w.org/"
Cache-Control: private, no-store, no-cache, must-revalidate
Expires: Tue, 19 May 2020 15:41:20 GMT
Content-Type: text/html; charset=UTF-8
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Length: unspecified [text/html]
Saving to: ‘index.html’
为了完整起见,请参阅我的博客的新 Apache 配置:
# avoids sending hackers too much info about the server
ServerTokens Prod
<VirtualHost *:8080>
ServerName www.example.com
ServerAdmin dagmar@example.com
ErrorLog /var/log/apache2/blog/error.log
CustomLog /var/log/apache2/blog/access.log common
DocumentRoot /var/www/blog
<Directory /var/www/blog>
AllowOverride All
Options -Indexes
</Directory>
# Enable Compression
<IfModule mod_deflate.c>
SetOutputFilter DEFLATE
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI \.(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary
Header append Vary User-Agent
</IfModule>
# Enable expires headers
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/pdf "access plus 1 month"
ExpiresByType text/x-javascript "access plus 1 month"
ExpiresByType text/javascript "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType application/x-javascript "access plus 1 month"
ExpiresByType image/x-icon "access plus 1 year"
ExpiresByType text/xml "access plus 0 seconds"
ExpiresByType text/html "access plus 0 seconds"
ExpiresByType text/plain "access plus 0 seconds"
ExpiresByType application/xml "access plus 0 seconds"
ExpiresByType application/json "access plus 0 seconds"
ExpiresByType application/rss+xml "access plus 1 hour"
ExpiresByType application/atom+xml "access plus 1 hour"
ExpiresByType text/x-component "access plus 1 hour"
ExpiresDefault "access plus 0 seconds"
</IfModule>
# Enable caching headers
<IfModule mod_headers.c>
# Calculate etag on modified time and file size (could be turned off too ?)
FileETag MTime Size
# NEVER CACHE - notice the extra directives
<FilesMatch "\.(html|htm|php)$">
Header set Cache-Control "private, no-store, no-cache, must-revalidate"
</FilesMatch>
</IfModule>