没有不值得去解决的问题,也没有不值得去学习的技术!

Fix WordPress Random Query String Cache Bypass With EdgeOne and Cloudflare: Optimize Canonical Post URLs Only

Figure 3: In EdgeOne, both the standard article URL and different random Query Strings hit the existing cache

作者:

,

Today I continued working on CDN caching issues for my WordPress sites.

While previously troubleshooting server CPU and PHP-FPM pressure, I found a scenario worth addressing:

Plaintext
https://www.shuijingwanwq.com/2026/07/27/20341/?abc=123
https://www.shuijingwanwq.com/2026/07/27/20341/?abc=456

The article content is actually identical, but the Query String after the URL differs. If the CDN treats these requests as different cache objects, it may continuously generate new MISSes and keep forwarding requests to the WordPress origin.

For standard article detail pages, these random parameters mostly have no practical meaning.

However, I cannot simply ignore Query Strings across the entire site, because WordPress itself has many requests that genuinely depend on parameters, such as:

Plaintext
/?s=wordpress
/?p=123
/?page_id=123

Therefore, the goal this time is not to “ignore parameters site-wide”, but rather:

Only normalize Query Strings for standard WordPress article detail pages.

My Chinese site uses Tencent Cloud EdgeOne, and my English site uses Cloudflare, so I completed two separate configurations and verified them through actual requests and Nginx logs.


1. Finalized Rule Boundaries

My article permalink structure is:

Plaintext
/YYYY/MM/DD/文章ID/

For example:

Plaintext
/2026/07/27/20341/

Initially, I considered handling both:

Plaintext
/2026/07/27/20341/
/2026/07/27/20341

Later, during actual testing, I found that this would make the rules increasingly complex.

In fact, a URL without a trailing slash is never the final canonical URL for an article anyway.

WordPress / Polylang handles:

Plaintext
/2026/07/27/20341
        ↓ 301
/2026/07/27/20341/

Therefore, I finally decided:

The CDN only applies special optimization to canonical article detail pages ending with /.

Meaning:

Plaintext
/YYYY/MM/DD/ID/

As for:

Plaintext
/YYYY/MM/DD/ID

WordPress / Polylang continues to handle the normal canonical 301.

This allows the Chinese and English sites to maintain the exact same design principles, and when I review the CDN configuration six months later, it will be easy to understand.


2. Chinese Site EdgeOne Configuration

Chinese site:

Plaintext
https://www.shuijingwanwq.com/

Currently accelerated via Tencent Cloud EdgeOne.

1. Matching Article Detail Pages

Create a rule in the EdgeOne Rule Engine.

Host:

Plaintext
www.shuijingwanwq.com

URL Path uses regex matching:

Plaintext
^/[0-9]{4}/[0-9]{2}/[0-9]{2}/[0-9]+/$

For example:

Plaintext
/2026/07/27/20341/

will match.

While:

Plaintext
/2026/07/27/20341

will not match.

It also will not affect:

Plaintext
/
/?s=wordpress
/category/php/
/tag/wordpress/
/2026/07/27/20341/feed/
Figure 1: EdgeOne Rule Engine matching only WordPress canonical article detail pages in the /YYYY/MM/DD/ID/ format
Figure 1: EdgeOne Rule Engine matching only WordPress canonical article detail pages in the /YYYY/MM/DD/ID/ format

2. Custom Cache Key

First operation:

Plaintext
Custom Cache Key
→ Query String
→ Ignore All

The goal is to make:

Plaintext
/2026/07/27/20341/
/2026/07/27/20341/?abc=111
/2026/07/27/20341/?abc=222

use the same cache object.


3. Delete Query String in Origin Pull Request

Second operation:

Plaintext
Origin Request Parameter Setting
→ Query String
→ Ignore All

This way, even on an EdgeOne MISS, when a client accesses:

Plaintext
/2026/07/27/20341/?abc=123

EdgeOne only requests the following during origin pull:

Plaintext
/2026/07/27/20341/

The random parameters will not proceed to the origin server.

Figure 2: EdgeOne configuring both "Custom Cache Key" and "Origin Request Parameter Setting" in the same rule, both ignoring Query String
Figure 2: EdgeOne configuring both “Custom Cache Key” and “Origin Request Parameter Setting” in the same rule, both ignoring Query String

3. EdgeOne Cache Key Actual Verification

After configuration, I first tested the same article.

Normal URL:

Plaintext
https://www.shuijingwanwq.com/2026/07/27/20341/

And different random parameters:

Plaintext
?swq_eo_final=111
?swq_eo_final=222

Test results:

Plaintext
With /, no parameters
HTTP/2 200
age: 4326
eo-cache-status: HIT

With /, random parameter 111
HTTP/2 200
age: 4334
eo-cache-status: HIT

With /, random parameter 222
HTTP/2 200
eo-cache-status: HIT

The most obvious part is:

Plaintext
No parameters        age: 4326
Parameter 111      age: 4334

Age continues to increase.

Moreover, a new Query String that has never been accessed before results in the following on the very first access:

Plaintext
HIT

This indicates that:

Plaintext
/20341/
/20341/?111
/20341/?222

have been normalized to the existing article cache.

Figure 3: In EdgeOne, both the standard article URL and different random Query Strings hit the existing cache
Figure 3: In EdgeOne, both the standard article URL and different random Query Strings hit the existing cache

4. EdgeOne Origin Pull Parameters Also Verified

Just seeing HIT is not enough.

I also need to prove:

When EdgeOne misses, the request received by the origin server has indeed had its Query String removed.

So I switched to a different article:

Plaintext
https://www.shuijingwanwq.com/2026/07/24/20084/

The client actually requested:

Plaintext
/2026/07/24/20084/?swq_eo_final_origin_1785162581209501862=1

EdgeOne returned:

Plaintext
HTTP/2 200
eo-cache-status: MISS

This indicates a real origin pull occurred this time.

Subsequently, I checked the server’s Nginx access log:

Plaintext
219.144.89.29 - - [27/Jul/2026:22:29:43 +0800]
"GET /2026/07/24/20084/ HTTP/1.1"
200 472412 "-"
"swq_eo_final_origin_1785162581209501862"

The client sent:

Plaintext
/20084/?swq_eo_final_origin_...=1

But Nginx actually received:

Plaintext
/20084/

Therefore, it can be confirmed that:

Plaintext
Client random Query String

EdgeOne MISS

Delete Query String

Origin server receives canonical URL

This part was not inferred from the console configuration, but actually verified through the origin server’s logs.

Figure 4: After an EdgeOne MISS, the Nginx log shows that the URL actually received by the origin server no longer contains the random Query String
Figure 4: After an EdgeOne MISS, the Nginx log shows that the URL actually received by the origin server no longer contains the random Query String

5. Why I Stopped Handling URLs Without a Trailing Slash

During testing, I also tested:

Plaintext
https://www.shuijingwanwq.com/2026/07/27/20341

Result:

Plaintext
HTTP/2 301
x-redirect-by: Polylang
location: https://www.shuijingwanwq.com/2026/07/27/20341/
eo-cache-status: MISS

With random parameters:

Plaintext
/20341?swq_eo_noslash=...

Also redirected by Polylang 301.

Initially, I considered adding an EdgeOne rule to have the edge node directly append / to this type of URL.

But after further consideration, I felt it was unnecessary.

The normal flow can perfectly be:

Plaintext
/20341?abc=123

WordPress / Polylang 301

/20341/?abc=123

EdgeOne canonical article rule

Hits /20341/ cache

The only cost is that the first request without a trailing slash requires WordPress to generate a 301.

Currently, there is no evidence that such requests are numerous enough to cause noticeable server pressure.

Adding extra CDN redirect rules just to eliminate a single 301 would increase long-term maintenance costs.

So the final principle is:

Only protect the true canonical URL, and do not keep piling up CDN rules for extremely low-probability scenarios.


6. English Site Cloudflare Configuration

English site:

Plaintext
https://en.shuijingwanwq.com/

Uses Cloudflare.

Here I achieve the same goal:

Plaintext
/YYYY/MM/DD/ID/?random_parameters

Ultimately shares the cache with:

Plaintext
/YYYY/MM/DD/ID/

.


1. Using URL Rewrite Rule

The Cloudflare Free plan rules interface does not directly provide the regex matching capabilities I need, so I ultimately used the Rules Language string functions to restrict the article path.

The final condition is roughly:

Plaintext
(
  http.host eq "en.shuijingwanwq.com"
  and starts_with(http.request.uri.path, "/20")
  and substring(http.request.uri.path, 5, 6) eq "/"
  and substring(http.request.uri.path, 8, 9) eq "/"
  and substring(http.request.uri.path, 11, 12) eq "/"
  and ends_with(http.request.uri.path, "/")
  and substring(http.request.uri.path, 12, -1) ne ""
  and not (substring(http.request.uri.path, 12, -1) contains "/")
  and http.request.uri.query ne ""
)

The target is still only:

Plaintext
/2026/07/14/19522/

And not:

Plaintext
/2026/07/14/19522
/2026/07/14/19522/feed/
/2026/07/14/19522/embed/
Figure 5: Cloudflare URL Rewrite Rule restricting the English site canonical article detail page
Figure 5: Cloudflare URL Rewrite Rule restricting the English site canonical article detail page

2. Do Not Modify Path, Only Delete Query

Action configuration:

Plaintext
Path:
Preserve

Query:
Rewrite to
Static
Empty value

Meaning:

Plaintext
/2026/07/14/19522/?abc=123

is processed internally by Cloudflare as:

Plaintext
/2026/07/14/19522/

The path itself remains unchanged.

Figure 6: Cloudflare URL Rewrite Rule preserves the Path and only rewrites the Query to an empty value
Figure 6: Cloudflare URL Rewrite Rule preserves the Path and only rewrites the Query to an empty value

7. Cloudflare Origin Pull Query String Deletion Verification

First test with random parameters:

Plaintext
/2026/07/14/19522/?swq_cf_slash=...

Cloudflare returned:

Plaintext
HTTP/2 200
cf-cache-status: MISS

Subsequently, I found the following in the server’s Nginx access log:

Plaintext
162.158.110.160 - - [27/Jul/2026:22:09:39 +0800]
"GET /2026/07/14/19522/ HTTP/2.0"
200 50901 "-" "curl/8.18.0"

Proving once again that:

Plaintext
Client:
/19522/?random_parameters

        ↓ Cloudflare

Origin server:
/19522/

The Query String did not reach WordPress.

Figure 7: The Nginx log corresponding to the Cloudflare MISS request no longer shows the client's random parameters
Figure 7: The Nginx log corresponding to the Cloudflare MISS request no longer shows the client’s random parameters

8. Does Cloudflare Really Share the Cache?

Just proving “the origin pull has no parameters” is not enough.

The more critical question is:

Plaintext
/19522/

and:

Plaintext
/19522/?abc=123

Do they really use the same Cloudflare CDN cache entry?

So I conducted consecutive tests.

Results:

Plaintext
Standard URL first time
MISS

Standard URL second time
HIT
age: 5

Parameter 111
HIT
age: 8

Parameter 222
HIT
age: 11

Parameter 333
HIT
age: 16

Standard URL again
HIT
age: 19

And all these requests landed on:

Plaintext
AMS

the same Cloudflare node.

This result is already very clear:

Plaintext
/19522/
/19522/?111
/19522/?222
/19522/?333

All hit the same existing cache entry.

Particularly:

Plaintext
111
222
333

These are all new parameters that had not been accessed before, yet the very first request directly yielded:

Plaintext
CF-Cache-Status: HIT

And:

Plaintext
Age: 5 → 8 → 11 → 16 → 19

continuously increased.

Therefore, there is no need to create an additional Cloudflare Cache Rule.

A single URL Rewrite Rule has already fulfilled the current requirement.

Figure 8: Cloudflare consecutive HITs with different Query Strings and continuously increasing Age, proving cache sharing with the standard URL
Figure 8: Cloudflare consecutive HITs with different Query Strings and continuously increasing Age, proving cache sharing with the standard URL

9. Cloudflare Trailing Slash End-to-End Verification

Finally, I also tested:

Plaintext
/2026/07/14/19522?random_parameters

Letting curl automatically follow the 301.

Result of the first hop:

Plaintext
HTTP/2 301

location:
https://en.shuijingwanwq.com/2026/07/14/19522/?swq_cf_e2e_1785162314320989211=1

x-redirect-by: Polylang
cf-cache-status: MISS

Meaning:

Plaintext
/19522?random_parameters

Polylang

/19522/?random_parameters

Second hop:

Plaintext
HTTP/2 200
age: 524
cf-cache-status: HIT

The complete path becomes:

Plaintext
/19522?random=1

Polylang 301

/19522/?random=1

Cloudflare URL Rewrite

Query String normalized

Hits existing /19522/ cache

Therefore, even without specifically optimizing URLs without a trailing slash, the request will ultimately return to the already optimized canonical CDN cache path.

Figure 9: After the Cloudflare trailing slash article URL goes through a Polylang 301, the second hop directly hits the existing CDN cache
Figure 9: After the Cloudflare trailing slash article URL goes through a Polylang 301, the second hop directly hits the existing CDN cache

10. Chinese and English Sites Finally Unified into the Same Design

After completing this round of adjustments, although the implementation methods of the two CDNs differ, their design philosophy is completely identical.

Chinese site EdgeOne:

Plaintext
www.shuijingwanwq.com

/YYYY/MM/DD/ID/

Query String does not participate in Cache Key

Different parameters share cache
        ↓ MISS
Origin pull deletes Query String

English site Cloudflare:

Plaintext
en.shuijingwanwq.com

/YYYY/MM/DD/ID/?parameters

URL Rewrite deletes Query String

Shares cache with canonical URL
        ↓ MISS
Origin server receives parameterless URL

And for those without a trailing slash:

Plaintext
/YYYY/MM/DD/ID

Both sides maintain the original canonical behavior of WordPress / Polylang:

Plaintext
/ID
↓ 301
/ID/

No longer adding special CDN logic for this layer.


11. In This Configuration, I Ultimately Valued “Simplicity” More

During this configuration process, there were actually many opportunities to continue optimizing.

For example:

  • EdgeOne could additionally perform an edge 301 for missing trailing slashes;
  • Cloudflare could add more Cache Rules;
  • Various /feed/, /embed/, and special parameter combinations could be further split and handled individually.

But when it comes to CDN configuration, more is not always better.

As rules continue to increase, another problem arises:

Six months later, even I would have trouble confirming exactly which rule a request hit.

So this time I ultimately chose a very clear boundary:

The CDN is only responsible for Query String cache normalization of canonical article URLs.

Issues that WordPress itself can handle normally, such as canonical 301s for missing trailing slashes, are left for WordPress to continue handling.

This design may not be theoretically “perfectly optimized”, but it is easier to maintain and better fits the actual needs of my current personal WordPress site.


12. Cloudflare 522 / 525 Still Occurred During Testing

While testing the English site, I also encountered:

Plaintext
522
525

multiple times. And I had noticed similar phenomena previously when publishing articles:

The first access might result in a Cloudflare 522 / 525, but requesting it again returns to normal.

A similar situation occurred during this test as well.

For example, when accessing from my home computer, some requests landed on:

Plaintext
LAX
LAS

and resulted in 522 / 525.

Later, when requesting directly from the server terminal, the requests landed on:

Plaintext
AMS

The complete:

Plaintext
301 → HIT

path was able to complete normally.

Currently, the server reports:

Plaintext
load average: 0.98, 0.90, 1.15

Memory:

Plaintext
Total: 1.9 GiB
Available: 889 MiB

And port 443 is normally listened to by Nginx.

Therefore, at this stage, it is not possible to conclude solely based on 522 / 525 that the ECS hardware is definitely insufficient.

Of course, I still believe that server performance might be one of the factors, and I may eventually need to upgrade the ECS.

But for now, I will not continue troubleshooting this issue.

This time, I first complete:

WordPress article Query String cache normalization for EdgeOne + Cloudflare.

The 522 / 525 issue will be left for later analysis as a separate problem, to avoid mixing CDN cache rules with origin server stability.


13. Final Result

At this point, the article detail pages for both frontend domains have achieved:

Plaintext
Random Query String

Will not continuously create new article cache objects

Canonical URL shares CDN cache

And when an actual origin pull is truly needed:

Plaintext
Request with random parameters

CDN

Origin server receives parameterless canonical URL

Most importantly, these conclusions were not judged solely based on the CDN console configuration, but were verified step by step through:

Plaintext
HIT / MISS
Age
301
Location
CF-Ray
Nginx access log

.

The final rules have also converged from the initial “cover all scenarios as much as possible” into a very easy-to-understand model:

Plaintext
Only /YYYY/MM/DD/ID/
falls under the CDN article detail page special optimization scope.

For my current website, I prefer this outcome.

Because it not only solves the cache penetration issue caused by random Query Strings, but also avoids turning the CDN configuration into another complex system that is difficult to maintain.

As for the occasional Cloudflare 522 / 525, that will be left for the next phase to decide separately: whether to continue optimizing the server configuration or directly upgrade the ECS hardware.

系列导航

需要长期技术维护或远程问题排查?

我是拥有 15+ 年经验的 PHP / Go 后端工程师,长期关注已有系统维护、Bug 修复、性能优化、服务器排查、WordPress 网站维护和小功能迭代。

如果你的项目遇到以下情况,可以先从一次小问题排查开始合作:

  • ✅ PHP / Laravel / Yii2 老项目无人维护
  • ✅ Go / Gin 后端接口需要排查或优化
  • ✅ WordPress 网站访问慢、报错或插件冲突
  • ✅ Nginx / MySQL / Redis / Linux 服务器异常
  • ✅ CDN / Cloudflare / DNS / HTTPS 配置问题
  • ✅ 需要长期远程技术支持或兼职维护

更多介绍请查看:关于我 & 合作

微信:13980074657
邮箱:shuijingwanwq@gmail.com
Telegram:@shuijingwan
GitHub:https://github.com/shuijingwan