好久没写过 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的后台看到这样的报告:
查看图片
所以这是成功了?
大佬,我是结合https://sleele.com/2021/03/26/edge-cache-html-via-cloudflare-workers/和您的文章一起看的。我对于“添加Route并绑定Workers脚本”这里十分费解。
因为现在CloudFlare的后台和您写文章时已经大不相同,所以我也不知道自己设置的对不对:
查看图片
Route功能好像已经内置到Worker的触发器里面了。但我也不知道要怎么启用,似乎没有提供相关的选项。我检查了自己网站请求时的header,似乎并没有类似sleele大佬的成功记录:
查看图片
看看是什么情况?谢谢哈
你这个不是没问题嘛,我看你网站也是有缓存的呀~
PS:友链加了哦,网站的背景图真好看|´・ω・)ノ
谢谢互链!我这个图片是转载别人的 我自己的网站好像没成功。。( ̄△ ̄;)
我看是有缓存的了,你可以试试清理下你浏览器的缓存或者强制刷新下页面再看看 header。
我清缓存后看还是一样的 比如我看一张图片:
cf-cache-status: HIT
应该只能说明在Cloudflare缓存成功,任何开了小黄云的网站应该都会有这个吧?这应该不能说明Workers生效了吧开启CF Workers,请问会否对原有的缓存插件有影响?
没什么影响,用了这个就相当于是在缓存插件之上又多了一层缓存,用户访问时先看到的是 Cloudflare 的缓存,Cloudflare 访问源站时拉取的是缓存插件缓存过的页面。
新年快乐~2021年要开开心心吖ヾ(≧∇≦*)ゝ
哇!谢谢!希望新的一年大家都能健健康康开开心心的!୧(๑•̀⌄•́๑)૭