From e0eded21547b5da83f2ec6f42c220018e1b1f286 Mon Sep 17 00:00:00 2001 From: Yilia Lin Date: Sat, 10 Oct 2026 18:44:22 +0800 Subject: [PATCH] fix(seo): align indexable pages with redirect behavior --- .htaccess | 3 ++- next/scripts/check-ingress-redirects.mjs | 12 ++++++++++++ next/scripts/generate-sitemaps.mjs | 2 ++ next/scripts/generate-sitemaps.test.mjs | 4 ++++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/.htaccess b/.htaccess index ff239e7de1bec..7877e305aeacf 100644 --- a/.htaccess +++ b/.htaccess @@ -310,4 +310,5 @@ RedirectMatch 301 "^(/zh)?/docs/apisix/en/latest/deployment-modes(\.md)?/?$" "$1 # and a self-referential canonical, so 18 near-duplicates competed with the # pages they duplicated. The listing at /zh/learning-center/ now links to the # English articles directly; these URLs are indexed, so send them there. -RedirectMatch 301 "^/zh/learning-center/(.+)$" "/learning-center/$1" +# DirectoryIndex resolves the listing through index.html; leave that file alone. +RedirectMatch 301 "^/zh/learning-center/(?!index\.html$)(.+)$" "/learning-center/$1" diff --git a/next/scripts/check-ingress-redirects.mjs b/next/scripts/check-ingress-redirects.mjs index 8136479fe9cd7..06384be72c008 100644 --- a/next/scripts/check-ingress-redirects.mjs +++ b/next/scripts/check-ingress-redirects.mjs @@ -132,6 +132,10 @@ const directRedirects = [ '/docs/ingress-controller/1.8.0/FAQ/', '/docs/ingress-controller/overview/', ], + [ + '/docs/ingress-controller/FAQ/', + '/docs/ingress-controller/overview/', + ], [ '/docs/ingress-controller/reference/apisix-ingress-controller/crd-reference/', '/docs/ingress-controller/reference/apisix-ingress-controller/api-reference/', @@ -187,4 +191,12 @@ assert.equal( 'Redirect directives should only match complete path segments', ); +for (const listingPath of ['/zh/learning-center/', '/zh/learning-center/index.html']) { + assert.equal(firstRedirect(listingPath), null, `${listingPath} should remain a Chinese listing`); +} +assert.deepEqual(firstRedirect('/zh/learning-center/what-is-an-api-gateway/'), { + status: 301, + destination: '/learning-center/what-is-an-api-gateway/', +}); + console.log(`Validated ${directRedirects.length} direct documentation redirects.`); diff --git a/next/scripts/generate-sitemaps.mjs b/next/scripts/generate-sitemaps.mjs index 3e24112b08ae5..af2670b6c1d36 100644 --- a/next/scripts/generate-sitemaps.mjs +++ b/next/scripts/generate-sitemaps.mjs @@ -19,6 +19,8 @@ const excludePatterns = [ /^\/(?:zh\/)?docs\/[\w-]+\/(?:[\w-]+-)?\d+\.\d+(?:\.\d+)?\//, /^\/(?:zh\/)?docs\/[\w./-]+\/tags\//, /^\/(?:zh\/)?docs\/[\w-]+\/next\//, + // The current Ingress FAQ is a 301 alias for the overview, not an indexable page. + /^\/(?:zh\/)?docs\/ingress-controller\/FAQ\/$/, /^\/(?:zh\/)?search\/?$/, /^\/(?:zh\/)?blog\/(?:tags|page|archive)\//, /^\/(?:zh\/)?learning-center\/(?:tags|page|archive)\//, diff --git a/next/scripts/generate-sitemaps.test.mjs b/next/scripts/generate-sitemaps.test.mjs index 0a74d9c0d9729..a7cc29267232a 100644 --- a/next/scripts/generate-sitemaps.test.mjs +++ b/next/scripts/generate-sitemaps.test.mjs @@ -62,6 +62,7 @@ const pages = [ 'docs/apisix/next/plugins/cors', 'docs/apisix/tags/plugins', 'docs/apisix/upgrade-guide-from-2.15.x-to-3.0.0', + 'docs/ingress-controller/FAQ', 'search', 'zh', 'zh/learning-center', @@ -75,6 +76,7 @@ const pages = [ 'zh/blog/page/2', 'zh/blog/2026/07/28/bi-weekly report', 'zh/docs/ingress-controller/2.1.0/overview', + 'zh/docs/ingress-controller/FAQ', 'zh/docs/apisix/next/plugins/cors', 'zh/docs/apisix/tags/plugins', 'zh/search', @@ -120,8 +122,10 @@ try { 'docs/docker/apisix-3.17.0/build', 'docs/apisix/next', 'docs/apisix/next/plugins/cors', + 'docs/ingress-controller/FAQ', 'docs/apisix/tags/plugins', 'zh/docs/ingress-controller/2.1.0/overview', + 'zh/docs/ingress-controller/FAQ', 'zh/docs/apisix/next/plugins/cors', 'zh/docs/apisix/tags/plugins', '/search/',