好久没写过 WordPress 相关的东西了,这次会想起来写是因为最近看到了 Cloudflare 出的一个新功能,叫 Automatic Platform Optimization for WordPress,这个功能是专门为 WordPress 推出的,用处就是和他家的 WordPress 插件配合着用来优化你的 WordPress 网站,最关键的是,这次可以用它来缓存 HTML 了!然而比较遗憾的是,这是个付费功能,要用的话要么每月付费 5 美元单独开通这个功能,要么开一个自带此功能 Pro 套餐,每月 20 刀,虽然我是挺心动这个功能的,不过苦于囊中羞涩,想了想只能是放弃了。
虽然是不能用了,不过官方的博客在介绍这个功能时,有提到缓存 HTML 用的是他家的 Workers 来实现的,而用 Workers 来缓存 HTML 其实官方以前就有出过教程,只不过那时候 Workers KV 这个功能还不是免费的,导致在清除缓存时只能借助全局 API 的方式来清除,弊端就是这个清除是不分缓存类型的,会把其它资源的缓存给一块清除了,会比较浪费,所以我当初试了几天最终还是放弃折腾了。好巧不巧的是,在官方推出 Automatic Platform Optimization for WordPress 不久,Cloudflare 后面又给免费用户开放了 Workers KV 的使用,虽然和 Workers 一样是有限制的,但是我想了想,用来给自己的博客用好像也没什么问题,毕竟我的博客负载不高,加上 Workers 超额了也可以设置直接返回源站,这样子在限额没到的时候用 Workers 缓存网页可以提高网站的访问速度,而限额到了也只是返回源站,和现在的体验没什么差别,所以虽然是不能用最好的官方支援功能了,自己折腾折腾 Workers 用个低配版的也不错嘛!
基于以上的原因,所以我决定抄一抄官方的例子,配合现在开放的 Workers KV 功能来弄一个低配版的 HTML 页面缓存功能。因为其实就是照抄官方的例子弄好的,所以我本来没打算写教程分享的,只是看了下网上比较热门的文章,很多针对 Workers 的都是在把它当代理用的,其它方面的分享似乎不是很多,所以想了想还是决定水一篇比较简单的教程,算是分享点经验给也有此想法的朋友吧~
注意:官方给出的例子里面有两种使用方法,一种是 KV的(推荐),一种是 API 的,由于我上面说的原因,再加上 KV 现在也可以免费用了,所以下面的教程只针对 Workers KV 来写,不包含 API 的设置方法。
一、添加 Workers KV 命名空间
在开始之前,我们需要先添加一个 Workers KV 的命名空间,后面 Workers 有关的数据就会存储在这里面。添加方法也比较简单,我直接截图吧!
根据我上面的两张图来添加命名空间就可以了,命名空间的名字大家可以自己随便设置,根据官方的说法,用已经添加好的也是没问题的,所以如果你已经有添加过命名空间的话,这一步是可以不用做的。
二、设置 Workers 脚本
找到下图的位置,然后添加 Workers 脚本:
点击上面的创建功能后,你会看到一个类似于下图的页面:
看到这个页面后,先把最左边框出来的示例代码给全部删除了,然后复制下面的代码添加进去,最后点击页面左下的“Save and Deploy”就可以了。
PS:忘记说了,脚本的名字在我框出来的这部分的上面,默认是随机的名字,你可以自己改一个好识别的名字,名字不影响功能的使用。
代码如下:
// IMPORTANT: Either A Key/Value Namespace must be bound to this worker script
// using the variable name EDGE_CACHE. or the API parameters below should be
// configured. KV is recommended if possible since it can purge just the HTML
// instead of the full cache.
// API settings if KV isn't being used
const CLOUDFLARE_API = {
email: "", // From https://dash.cloudflare.com/profile
key: "", // Global API Key from https://dash.cloudflare.com/profile
zone: "" // "Zone ID" from the API section of the dashboard overview page https://dash.cloudflare.com/
};
// Default cookie prefixes for bypass
const DEFAULT_BYPASS_COOKIES = [
"wp-",
"wordpress",
"comment_",
"woocommerce_"
];
/**
* Main worker entry point.
*/
addEventListener("fetch", event => {
const request = event.request;
let upstreamCache = request.headers.get('x-HTML-Edge-Cache');
// Only process requests if KV store is set up and there is no
// HTML edge cache in front of this worker (only the outermost cache
// should handle HTML caching in case there are varying levels of support).
let configured = false;
if (typeof EDGE_CACHE !== 'undefined') {
configured = true;
} else if (CLOUDFLARE_API.email.length && CLOUDFLARE_API.key.length && CLOUDFLARE_API.zone.length) {
configured = true;
}
// Bypass processing of image requests (for everything except Firefox which doesn't use image/*)
const accept = request.headers.get('Accept');
let isImage = false;
if (accept && (accept.indexOf('image/*') !== -1)) {
isImage = true;
}
if (configured && !isImage && upstreamCache === null) {
event.passThroughOnException();
event.respondWith(processRequest(request, event));
}
});
/**
* Process every request coming through to add the edge-cache header,
* watch for purge responses and possibly cache HTML GET requests.
*
* @param {Request} originalRequest - Original request
* @param {Event} event - Original event (for additional async waiting)
*/
async function processRequest(originalRequest, event) {
let cfCacheStatus = null;
const accept = originalRequest.headers.get('Accept');
const isHTML = (accept && accept.indexOf('text/html') >= 0);
let {response, cacheVer, status, bypassCache} = await getCachedResponse(originalRequest);
if (response === null) {
// Clone the request, add the edge-cache header and send it through.
let request = new Request(originalRequest);
request.headers.set('x-HTML-Edge-Cache', 'supports=cache|purgeall|bypass-cookies');
response = await fetch(request);
if (response) {
const options = getResponseOptions(response);
if (options && options.purge) {
await purgeCache(cacheVer, event);
status += ', Purged';
}
bypassCache = bypassCache || shouldBypassEdgeCache(request, response);
if ((!options || options.cache) && isHTML &&
originalRequest.method === 'GET' && response.status === 200 &&
!bypassCache) {
status += await cacheResponse(cacheVer, originalRequest, response, event);
}
}
} else {
// If the origin didn't send the control header we will send the cached response but update
// the cached copy asynchronously (stale-while-revalidate). This commonly happens with
// a server-side disk cache that serves the HTML directly from disk.
cfCacheStatus = 'HIT';
if (originalRequest.method === 'GET' && response.status === 200 && isHTML) {
bypassCache = bypassCache || shouldBypassEdgeCache(originalRequest, response);
if (!bypassCache) {
const options = getResponseOptions(response);
if (!options) {
status += ', Refreshed';
event.waitUntil(updateCache(originalRequest, cacheVer, event));
}
}
}
}
if (response && status !== null && originalRequest.method === 'GET' && response.status === 200 && isHTML) {
response = new Response(response.body, response);
response.headers.set('x-HTML-Edge-Cache-Status', status);
if (cacheVer !== null) {
response.headers.set('x-HTML-Edge-Cache-Version', cacheVer.toString());
}
if (cfCacheStatus) {
response.headers.set('CF-Cache-Status', cfCacheStatus);
}
}
return response;
}
/**
* Determine if the cache should be bypassed for the given request/response pair.
* Specifically, if the request includes a cookie that the response flags for bypass.
* Can be used on cache lookups to determine if the request needs to go to the origin and
* origin responses to determine if they should be written to cache.
* @param {Request} request - Request
* @param {Response} response - Response
* @returns {bool} true if the cache should be bypassed
*/
function shouldBypassEdgeCache(request, response) {
let bypassCache = false;
if (request && response) {
const options = getResponseOptions(response);
const cookieHeader = request.headers.get('cookie');
let bypassCookies = DEFAULT_BYPASS_COOKIES;
if (options) {
bypassCookies = options.bypassCookies;
}
if (cookieHeader && cookieHeader.length && bypassCookies.length) {
const cookies = cookieHeader.split(';');
for (let cookie of cookies) {
// See if the cookie starts with any of the logged-in user prefixes
for (let prefix of bypassCookies) {
if (cookie.trim().startsWith(prefix)) {
bypassCache = true;
break;
}
}
if (bypassCache) {
break;
}
}
}
}
return bypassCache;
}
const CACHE_HEADERS = ['Cache-Control', 'Expires', 'Pragma'];
/**
* Check for cached HTML GET requests.
*
* @param {Request} request - Original request
*/
async function getCachedResponse(request) {
let response = null;
let cacheVer = null;
let bypassCache = false;
let status = 'Miss';
// Only check for HTML GET requests (saves on reading from KV unnecessarily)
// and not when there are cache-control headers on the request (refresh)
const accept = request.headers.get('Accept');
const cacheControl = request.headers.get('Cache-Control');
let noCache = false;
if (cacheControl && cacheControl.indexOf('no-cache') !== -1) {
noCache = true;
status = 'Bypass for Reload';
}
if (!noCache && request.method === 'GET' && accept && accept.indexOf('text/html') >= 0) {
// Build the versioned URL for checking the cache
cacheVer = await GetCurrentCacheVersion(cacheVer);
const cacheKeyRequest = GenerateCacheRequest(request, cacheVer);
// See if there is a request match in the cache
try {
let cache = caches.default;
let cachedResponse = await cache.match(cacheKeyRequest);
if (cachedResponse) {
// Copy Response object so that we can edit headers.
cachedResponse = new Response(cachedResponse.body, cachedResponse);
// Check to see if the response needs to be bypassed because of a cookie
bypassCache = shouldBypassEdgeCache(request, cachedResponse);
// Copy the original cache headers back and clean up any control headers
if (bypassCache) {
status = 'Bypass Cookie';
} else {
status = 'Hit';
cachedResponse.headers.delete('Cache-Control');
cachedResponse.headers.delete('x-HTML-Edge-Cache-Status');
for (header of CACHE_HEADERS) {
let value = cachedResponse.headers.get('x-HTML-Edge-Cache-Header-' + header);
if (value) {
cachedResponse.headers.delete('x-HTML-Edge-Cache-Header-' + header);
cachedResponse.headers.set(header, value);
}
}
response = cachedResponse;
}
} else {
status = 'Miss';
}
} catch (err) {
// Send the exception back in the response header for debugging
status = "Cache Read Exception: " + err.message;
}
}
return {response, cacheVer, status, bypassCache};
}
/**
* Asynchronously purge the HTML cache.
* @param {Int} cacheVer - Current cache version (if retrieved)
* @param {Event} event - Original event
*/
async function purgeCache(cacheVer, event) {
if (typeof EDGE_CACHE !== 'undefined') {
// Purge the KV cache by bumping the version number
cacheVer = await GetCurrentCacheVersion(cacheVer);
cacheVer++;
event.waitUntil(EDGE_CACHE.put('html_cache_version', cacheVer.toString()));
} else {
// Purge everything using the API
const url = "https://api.cloudflare.com/client/v4/zones/" + CLOUDFLARE_API.zone + "/purge_cache";
event.waitUntil(fetch(url,{
method: 'POST',
headers: {'X-Auth-Email': CLOUDFLARE_API.email,
'X-Auth-Key': CLOUDFLARE_API.key,
'Content-Type': 'application/json'},
body: JSON.stringify({purge_everything: true})
}));
}
}
/**
* Update the cached copy of the given page
* @param {Request} originalRequest - Original Request
* @param {String} cacheVer - Cache Version
* @param {EVent} event - Original event
*/
async function updateCache(originalRequest, cacheVer, event) {
// Clone the request, add the edge-cache header and send it through.
let request = new Request(originalRequest);
request.headers.set('x-HTML-Edge-Cache', 'supports=cache|purgeall|bypass-cookies');
response = await fetch(request);
if (response) {
status = ': Fetched';
const options = getResponseOptions(response);
if (options && options.purge) {
await purgeCache(cacheVer, event);
}
let bypassCache = shouldBypassEdgeCache(request, response);
if ((!options || options.cache) && !bypassCache) {
await cacheResponse(cacheVer, originalRequest, response, event);
}
}
}
/**
* Cache the returned content (but only if it was a successful GET request)
*
* @param {Int} cacheVer - Current cache version (if already retrieved)
* @param {Request} request - Original Request
* @param {Response} originalResponse - Response to (maybe) cache
* @param {Event} event - Original event
* @returns {bool} true if the response was cached
*/
async function cacheResponse(cacheVer, request, originalResponse, event) {
let status = "";
const accept = request.headers.get('Accept');
if (request.method === 'GET' && originalResponse.status === 200 && accept && accept.indexOf('text/html') >= 0) {
cacheVer = await GetCurrentCacheVersion(cacheVer);
const cacheKeyRequest = GenerateCacheRequest(request, cacheVer);
try {
// Move the cache headers out of the way so the response can actually be cached.
// First clone the response so there is a parallel body stream and then
// create a new response object based on the clone that we can edit.
let cache = caches.default;
let clonedResponse = originalResponse.clone();
let response = new Response(clonedResponse.body, clonedResponse);
for (header of CACHE_HEADERS) {
let value = response.headers.get(header);
if (value) {
response.headers.delete(header);
response.headers.set('x-HTML-Edge-Cache-Header-' + header, value);
}
}
response.headers.delete('Set-Cookie');
response.headers.set('Cache-Control', 'public; max-age=315360000');
event.waitUntil(cache.put(cacheKeyRequest, response));
status = ", Cached";
} catch (err) {
// status = ", Cache Write Exception: " + err.message;
}
}
return status;
}
/******************************************************************************
* Utility Functions
*****************************************************************************/
/**
* Parse the commands from the x-HTML-Edge-Cache response header.
* @param {Response} response - HTTP response from the origin.
* @returns {*} Parsed commands
*/
function getResponseOptions(response) {
let options = null;
let header = response.headers.get('x-HTML-Edge-Cache');
if (header) {
options = {
purge: false,
cache: false,
bypassCookies: []
};
let commands = header.split(',');
for (let command of commands) {
if (command.trim() === 'purgeall') {
options.purge = true;
} else if (command.trim() === 'cache') {
options.cache = true;
} else if (command.trim().startsWith('bypass-cookies')) {
let separator = command.indexOf('=');
if (separator >= 0) {
let cookies = command.substr(separator + 1).split('|');
for (let cookie of cookies) {
cookie = cookie.trim();
if (cookie.length) {
options.bypassCookies.push(cookie);
}
}
}
}
}
}
return options;
}
/**
* Retrieve the current cache version from KV
* @param {Int} cacheVer - Current cache version value if set.
* @returns {Int} The current cache version.
*/
async function GetCurrentCacheVersion(cacheVer) {
if (cacheVer === null) {
if (typeof EDGE_CACHE !== 'undefined') {
cacheVer = await EDGE_CACHE.get('html_cache_version');
if (cacheVer === null) {
// Uninitialized - first time through, initialize KV with a value
// Blocking but should only happen immediately after worker activation.
cacheVer = 0;
await EDGE_CACHE.put('html_cache_version', cacheVer.toString());
} else {
cacheVer = parseInt(cacheVer);
}
} else {
cacheVer = -1;
}
}
return cacheVer;
}
/**
* Generate the versioned Request object to use for cache operations.
* @param {Request} request - Base request
* @param {Int} cacheVer - Current Cache version (must be set)
* @returns {Request} Versioned request object
*/
function GenerateCacheRequest(request, cacheVer) {
let cacheUrl = request.url;
if (cacheUrl.indexOf('?') >= 0) {
cacheUrl += '&';
} else {
cacheUrl += '?';
}
cacheUrl += 'cf_edge_cache_ver=' + cacheVer;
return new Request(cacheUrl);
}
注意,上面的代码来自于 Cloudflare 官方的 Github 缓存 HTML 例子,具体出处:https://github.com/cloudflare/worker-examples/tree/master/examples/edge-cache-html
官方使用的是 MIT 协议开源的,好像是要用代码得保留 MIT 的协议说明来着?因为我是直接写文章复制的代码不知道该怎么添加合适,所以就贴一下这个协议说明的网址吧:https://opensource.org/licenses/MIT
官方给的代码实际上是可以直接用的,不需要怎么修改,不过还是有几个需要注意的地方,我贴出来说明一下吧。
const CLOUDFLARE_API = {
email: "", // From https://dash.cloudflare.com/profile
key: "", // Global API Key from https://dash.cloudflare.com/profile
zone: "" // "Zone ID" from the API section of the dashboard overview page https://dash.cloudflare.com/
};上面代码是在完整代码最开头的部分,完整代码里已经有说明了,这个是只有 API 清除缓存的方法才需要自己设置的,因为我们用的是 KV 的方法,所以这一部分的代码可以不修改或者直接删除了,都是没有影响的。
const DEFAULT_BYPASS_COOKIES = [ "wp-", "wordpress", "comment_", "woocommerce_" ];
这串代码就在上面 API 设置部分代码的后面,作用的话就是设置哪些 Cookies 可以绕过缓存直接到源站获取页面。这部分代码官方的例子里已经有添加几个常用的 Cookies 了,一般不需要我们自己再改,如果你有特别需求的话,可以按照代码的格式自己修改。
三、给 Workers 脚本绑定 Workers KV
上面添加好脚本并保存好后,回到添加脚本的页面就可以看到自己设置好的脚本了,之后就是点击脚本进行绑定 KV 的设置了,如下图:
按上面的图设置好以后,点击“Save”保存就搞定了。
这里需要注意的地方有两点,最后这张图里面的 Variable name 这一项,必须要填写 EDGE_CACHE,因为这是 Workers 脚本代码里会调用到的,不能乱改,其次是 KV namespace 这里,选择的是我们前面添加的 KV 命名空间,不一定要跟我截图的一样,你自己创建的随便哪个命名空间都是可以的。
四、添加 Route 并绑定 Workers 脚本
上面的都设置好之后,就可以动手开始使用了。先返回到 Cloueflare Workers 功能的主界面,根据下图点击添加 Route。
之后会弹出设置 Route 的页面,如下图:
给大家解释一下上图各个设置的含义:
- Route:填写的是域名规则,也就是设置什么样的域名会匹配这条脚本代码,像我们用 Workers 来缓存 WordPress 页面的话,为了全部页面都能匹配到,填写“你自己的域名/*”这个样子就可以了,比如我上图的写法。如果你想自定义下,可以看官方文档的写法说明:https://developers.cloudflare.com/workers/platform/routes#matching-behavior
- Worker:选择要用的脚本,这里我们选择前面创建的那个脚本就可以了
- Failure mode for this route:点开“Request limit failure mode”这个选项的箭头会看到额外的选项,是让你选择当 Workers 免费额度用超之后怎么处理的。Fail closed (block)是停止代码,并返回错误页面,Fail open (proceed)是停止代码,但是不返回错误页面而是直接把请求交给源服务器。对于我们用来缓存页面来说,第二个选项是比较好的,不然等你额度超了之后,别人打开你的博客文章就都是看到的 Cloudflare 错误页面了。
五、安装 WordPress 插件
按照上面的步骤设置完毕之后,缓存功能就开始正常工作了,不过目前只能缓存成功,还没办法在更新修改文章之后清除缓存,所以我们需要再给 WordPress 安装一个插件来触发自动清除缓存的功能。
这个插件没有上架 WordPress 的插件中心,所以只能自己本地下载好之后手动安装了,怎么手动安装就不用我说了吧?
插件下载地址(项目文件里那个 zip 文件):https://github.com/cloudflare/worker-examples/tree/master/examples/edge-cache-html/WordPress%20Plugin
强迫症的个人备份,不想到上面下可以下我的备份(备份于:20201130):
要是上面两个链接都不想下载或者打不开的话,你也可以直接复制下面的插件代码,保存为 PHP 文件并打包为 zip 文件,之后一样可以上传到 WordPress 手动安装:
<?php
/*
Plugin Name: Cloudflare Page Cache
Plugin URI: https://github.com/cloudflare/worker-examples/tree/master/examples/edge-cache-html
Description: Cache HTML pages on the Cloudflare CDN when used with the page cache Worker.
Version: 1.4
Author: Patrick Meenan
Author URI: https://www.cloudflare.com/
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: cloudflare-page-cache
Domain Path: /languages
*/
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
// Callbacks that something changed
function cloudflare_page_cache_init_action() {
static $done = false;
if ( $done ) {
return;
}
$done = true;
// Add the edge-cache headers
if (!is_user_logged_in() ) {
header( 'x-HTML-Edge-Cache: cache,bypass-cookies=wp-|wordpress|comment_|woocommerce_' );
} else {
header( 'x-HTML-Edge-Cache: nocache' );
}
// Post ID is received
add_action( 'wp_trash_post', 'cloudflare_page_cache_purge1', 0 );
add_action( 'publish_post', 'cloudflare_page_cache_purge1', 0 );
add_action( 'edit_post', 'cloudflare_page_cache_purge1', 0 );
add_action( 'delete_post', 'cloudflare_page_cache_purge1', 0 );
add_action( 'publish_phone', 'cloudflare_page_cache_purge1', 0 );
// Coment ID is received
add_action( 'trackback_post', 'cloudflare_page_cache_purge2', 99 );
add_action( 'pingback_post', 'cloudflare_page_cache_purge2', 99 );
add_action( 'comment_post', 'cloudflare_page_cache_purge2', 99 );
add_action( 'edit_comment', 'cloudflare_page_cache_purge2', 99 );
add_action( 'wp_set_comment_status', 'cloudflare_page_cache_purge2', 99, 2 );
// No post_id is available
add_action( 'switch_theme', 'cloudflare_page_cache_purge1', 99 );
add_action( 'edit_user_profile_update', 'cloudflare_page_cache_purge1', 99 );
add_action( 'wp_update_nav_menu', 'cloudflare_page_cache_purge0' );
add_action( 'clean_post_cache', 'cloudflare_page_cache_purge1' );
add_action( 'transition_post_status', 'cloudflare_page_cache_post_transition', 10, 3 );
}
add_action( 'init', 'cloudflare_page_cache_init_action' );
// Add the response header to purge the cache. send_headers isn't always called
// so set it immediately when something changes.
function cloudflare_page_cache_purge() {
static $purged = false;
if (!$purged) {
$purged = true;
header( 'x-HTML-Edge-Cache: purgeall' );
}
}
function cloudflare_page_cache_purge0() {
cloudflare_page_cache_purge();
}
function cloudflare_page_cache_purge1( $param1 ) {
cloudflare_page_cache_purge();
}
function cloudflare_page_cache_purge2( $param1, $param2="" ) {
cloudflare_page_cache_purge();
}
function cloudflare_page_cache_post_transition( $new_status, $old_status, $post ) {
if ( $new_status != $old_status ) {
cloudflare_page_cache_purge();
}
}
代码我一个字都没改,作者、出处和开源协议之类的里面都写了,不放心的可以自己去比对~
插件安装好之后,也不需要设置什么,这个插件没有设置界面,安装好启用就可以了。
简单的给大家分析下这个插件是怎么配合 Workers 脚本实现缓存网页和自动清除网页缓存的吧,其实看上面不多的代码也能知道了,实际上插件干的事情不多,也就是添加了几组动作,在发布/删除/修改文章,有新评论/评论被编辑,或者是更改 WordPress 主题时触发有关代码,将插件默认添加的响应头 x-HTML-Edge-Cache 由缓存状态变更为需要清除缓存的 purgeall,然后 Workers 那边的脚本里由相关代码会检测 x-HTML-Edge-Cache 这个响应头,当检测到某个页面的响应头变更了需要清除缓存时,就会在 Cloudflare 里清除对应页面的缓存了。
六、检查功能是否有正常生效
按照上面的设置弄好之后,所以功能应该都是在正常工作了的,然后我教大家怎么来进行检测验证,因为这个缓存功能是对已登录用户没有用的(你总不想自己也看到的是缓存页面吧?),所以最好是借助一下网页测速之类的网站来进行检测,比如:https://gtmetrix.com
不需要登录注册,使用这个网站测试一下自己的博客,测试完成之后切换到“Waterfall”这一项,查看自己的网站地址(注意是自己网站的 HTML 页面地址,不是其它静态资源),在响应头也就是 Headers 这项里面,如果能找到下面这样的响应头,就是缓存功能在正常工作了:
x-html-edge-cache:cache,bypass-cookies=wp-|wordpress|comment_|woocommerce_ x-html-edge-cache-status:Hit x-html-edge-cache-version:0
这几个响应头简单解释下意思:
- x-html-edge-cache:显示页面缓存是否需要更新和具体的缓存规则
- x-html-edge-cache-status:显示页面缓存状态,显示 hit 就是缓存命中成功了
- x-html-edge-cache-version:缓存版本,当网站每次清除缓存时,这个数字就会发生变化
从上面这三项返回的数据,我们就可以判断缓存是不是在正常工作了,如果还要看自动清除缓存功能是不是正常的话,只需要在更新文章之类的操作之后,再用这个网站测试一下,查看 x-html-edge-cache-version 这里的数字是不是和上次测试的不一样,如果是的话就是缓存被清除过了。
结束
好啦,说到这里就差不多了。其实教程没什么难的,基本上就是照着官方的教程说明操作一遍就完事了,只不过我还额外补充了点东西,好让大家能更好理解。
最后感谢 Cloudflare 的官方例子,具体地址在这里:https://github.com/cloudflare/worker-examples/tree/master/examples/edge-cache-html
如果你对 Workers 感兴趣的话,官方还有给出其它 Workers 用法的例子,也可以看看:https://github.com/cloudflare/worker-examples
最后的最后,也祝 Cloudflare 10 周年快乐,希望以后能带给我们更多优化网站的功能,当然不收钱最好,嘿嘿嘿~
PS:找不到比较满意的配图了,就随便用了个 NASA 的图,出处:https://unsplash.com/photos/Q1p7bh3SHj8




















今天趁热打铁,将大佬教程进行了复现。因为CloudFlare的后台其实有比较大的变化,可能我的教程对小白来说也有一些参考价值吧!我对于测试有效性方面也进行了更加细致的描述。总之,谢谢大佬的教程了!WordPress博客的CDN工作算是完成了一大块了。详见教程:Docker系列 WordPress系列 通过Cloudflare Workers加速WordPress博客。欢迎指教ヾ(≧∇≦*)ゝ
好的呀,我都好久没折腾 Worker 了,正如你前面分享的那篇文章所说,估计我的坏掉了,回头还得学习下你的文章重新设置下∠( ᐛ 」∠)_
喔 我知道了!原来不能看某个图片 要看html这个网址(~ ̄▽ ̄)~ 我的结果如下,应该是生效了:
另外,我在worker的后台看到这样的报告:
![image-20220607111203377]()
查看图片
所以这是成功了?
大佬,我是结合https://sleele.com/2021/03/26/edge-cache-html-via-cloudflare-workers/和您的文章一起看的。我对于“添加Route并绑定Workers脚本”这里十分费解。
![image-20220607103911537]()
![]()
因为现在CloudFlare的后台和您写文章时已经大不相同,所以我也不知道自己设置的对不对:
查看图片
Route功能好像已经内置到Worker的触发器里面了。但我也不知道要怎么启用,似乎没有提供相关的选项。我检查了自己网站请求时的header,似乎并没有类似sleele大佬的成功记录:
查看图片
看看是什么情况?谢谢哈
你这个不是没问题嘛,我看你网站也是有缓存的呀~
PS:友链加了哦,网站的背景图真好看|´・ω・)ノ
谢谢互链!我这个图片是转载别人的 我自己的网站好像没成功。。( ̄△ ̄;)
我看是有缓存的了,你可以试试清理下你浏览器的缓存或者强制刷新下页面再看看 header。
我清缓存后看还是一样的 比如我看一张图片:
cf-cache-status: HIT应该只能说明在Cloudflare缓存成功,任何开了小黄云的网站应该都会有这个吧?这应该不能说明Workers生效了吧开启CF Workers,请问会否对原有的缓存插件有影响?
没什么影响,用了这个就相当于是在缓存插件之上又多了一层缓存,用户访问时先看到的是 Cloudflare 的缓存,Cloudflare 访问源站时拉取的是缓存插件缓存过的页面。
新年快乐~2021年要开开心心吖ヾ(≧∇≦*)ゝ
哇!谢谢!希望新的一年大家都能健健康康开开心心的!୧(๑•̀⌄•́๑)૭