This is an automated email from the ASF dual-hosted git repository.

morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris-website.git


The following commit(s) were added to refs/heads/master by this push:
     new 19a3d329c73 [fix] swizzle NotFound/Content and 301 unmatched 
/docs/dev/* in .htaccess (#3621)
19a3d329c73 is described below

commit 19a3d329c73d303d61bc7e7b515970aef6e3b680
Author: Mingyu Chen (Rayner) <[email protected]>
AuthorDate: Wed May 6 17:19:53 2026 -0700

    [fix] swizzle NotFound/Content and 301 unmatched /docs/dev/* in .htaccess 
(#3621)
    
    The previous fix only swizzled the outer @theme/NotFound, so DocRoot's
    fallback (@theme/NotFound/Content) still rendered the default Docusaurus
    copy for missing docs under /docs-next/dev/. And legacy /docs/dev/* with
    no 1:1 redirect target hit a SPA hydration mismatch and rendered blank.
    Now the inner Content is swizzled with the same dev-doc detection, and
    unmatched /docs/dev/* (en + zh-CN) is 301'd at the Apache layer before
    React boots.
    
    Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
---
 scripts/verify-htaccess.sh          |  91 +++++++++++++++++++++++
 src/theme/NotFound.js               | 142 ------------------------------------
 src/theme/NotFound/Content/index.js | 118 ++++++++++++++++++++++++++++++
 src/theme/NotFound/index.js         |  21 ++++++
 static/.htaccess                    |  23 ++++--
 5 files changed, 247 insertions(+), 148 deletions(-)

diff --git a/scripts/verify-htaccess.sh b/scripts/verify-htaccess.sh
new file mode 100755
index 00000000000..75ec7d77843
--- /dev/null
+++ b/scripts/verify-htaccess.sh
@@ -0,0 +1,91 @@
+#!/usr/bin/env bash
+# Local verification harness for static/.htaccess. Does NOT build the site —
+# only stages the dummy files needed to exercise the rewrite rules.
+#
+# Usage:
+#   bash scripts/verify-htaccess.sh start     # boot httpd in foreground 
(Ctrl-C to stop)
+#   bash scripts/verify-htaccess.sh test      # run curl assertions in another 
shell
+set -euo pipefail
+
+ROOT="${TMPDIR:-/tmp}/doris-htaccess-test"
+PORT=8000
+HTACCESS_SRC="$(cd "$(dirname "$0")/.." && pwd)/static/.htaccess"
+
+stage() {
+    rm -rf "$ROOT"
+    mkdir -p 
"$ROOT"/{docs/dev/install,docs-next/dev/getting-started/what-is-apache-doris,zh-CN}
+    cp "$HTACCESS_SRC" "$ROOT/.htaccess"
+
+    printf 'GENERIC_404\n' > "$ROOT/404.html"
+    printf 'ZH_404\n' > "$ROOT/zh-CN/404.html"
+    # Simulate a file emitted by createRedirects — must short-circuit the 
rewrite.
+    printf 'EXISTING_REDIRECT_FILE\n' > "$ROOT/docs/dev/install/index.html"
+    # The eventual 301 target.
+    printf 'NEW_DEV_LANDING\n' > 
"$ROOT/docs-next/dev/getting-started/what-is-apache-doris/index.html"
+
+    cat > "$ROOT/httpd.conf" <<EOF
+ServerName localhost
+Listen $PORT
+LoadModule mpm_event_module /usr/libexec/apache2/mod_mpm_event.so
+LoadModule unixd_module /usr/libexec/apache2/mod_unixd.so
+LoadModule authz_core_module /usr/libexec/apache2/mod_authz_core.so
+LoadModule rewrite_module /usr/libexec/apache2/mod_rewrite.so
+LoadModule headers_module /usr/libexec/apache2/mod_headers.so
+LoadModule dir_module /usr/libexec/apache2/mod_dir.so
+LoadModule mime_module /usr/libexec/apache2/mod_mime.so
+LoadModule log_config_module /usr/libexec/apache2/mod_log_config.so
+
+TypesConfig /private/etc/apache2/mime.types
+DirectoryIndex index.html
+
+ErrorLog $ROOT/error.log
+PidFile $ROOT/httpd.pid
+LogLevel warn rewrite:trace3
+
+DocumentRoot "$ROOT"
+<Directory "$ROOT">
+    AllowOverride All
+    Require all granted
+</Directory>
+EOF
+}
+
+case "${1:-}" in
+    start)
+        stage
+        echo "[stage] root: $ROOT"
+        echo "[stage] running httpd on http://localhost:$PORT (Ctrl-C to stop)"
+        echo "[stage] rewrite trace: tail -f $ROOT/error.log"
+        exec /usr/sbin/httpd -f "$ROOT/httpd.conf" -X
+        ;;
+    test)
+        BASE="http://localhost:$PORT";
+        run() {
+            local desc="$1" url="$2" want_code="$3" want_body_or_loc="$4"
+            local out code loc body
+            out="$(curl -sS -o "$ROOT/last-body" -w '%{http_code} 
%{redirect_url}' "$BASE$url")"
+            code="${out%% *}"
+            loc="${out#* }"
+            body="$(tr -d '\r\n' < "$ROOT/last-body")"
+            local got
+            if [[ "$want_code" == 301 ]]; then got="$loc"; else got="$body"; fi
+            if [[ "$code" == "$want_code" && "$got" == *"$want_body_or_loc"* 
]]; then
+                echo "PASS  $desc  -> $code"
+            else
+                echo "FAIL  $desc  url=$url  
expected=$want_code/$want_body_or_loc  got=$code/$got"
+                exit 1
+            fi
+        }
+        run 'legacy /docs/dev/<missing>      -> 301 new landing'           
'/docs/dev/gettingStarted/intro'   301 
'/docs-next/dev/getting-started/what-is-apache-doris'
+        run 'legacy /docs/dev/install/       -> 200 existing redirect file' 
'/docs/dev/install/'              200 'EXISTING_REDIRECT_FILE'
+        run 'zh-CN /docs/dev/<missing>       -> 301 zh-CN new landing'     
'/zh-CN/docs/dev/whatever'         301 
'/zh-CN/docs-next/dev/getting-started/what-is-apache-doris'
+        run 'random EN 404                   -> /404.html'                 
'/totally/missing/path'            404 'GENERIC_404'
+        run 'random zh-CN 404                -> /zh-CN/404.html'           
'/zh-CN/totally/missing/path'      404 'ZH_404'
+        run '/docs/devops bystander          -> not rewritten (404)'       
'/docs/devops'                     404 'GENERIC_404'
+        echo 'all assertions passed'
+        ;;
+    *)
+        echo "usage: bash $0 start|test"
+        exit 2
+        ;;
+esac
diff --git a/src/theme/NotFound.js b/src/theme/NotFound.js
deleted file mode 100644
index 79d1f819b79..00000000000
--- a/src/theme/NotFound.js
+++ /dev/null
@@ -1,142 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import Translate, { translate } from '@docusaurus/Translate';
-import { PageMetadata } from '@docusaurus/theme-common';
-import Layout from '@theme/Layout';
-import ExternalLink from '../components/external-link/external-link';
-import { ExternalLinkArrowIcon } from 
'@site/src/components/Icons/external-link-arrow-icon';
-
-// Legacy /docs/dev/* URLs may still be linked from external sites. Pages with 
a
-// 1:1 match under /docs-next/dev/ are redirected at build time; pages without
-// one land here. Detect the legacy prefix and show guidance to the new Dev 
docs
-// entry instead of the generic 404.
-const LEGACY_DEV_GUIDANCE = {
-    en: {
-        title: 'This Dev doc has moved',
-        description:
-            'The legacy /docs/dev/ tree has been retired. The page you 
requested is no longer available at this URL.',
-        linkLabel: 'Go to new Dev docs',
-        linkTo: '/docs-next/dev/getting-started/what-is-apache-doris',
-    },
-    'zh-CN': {
-        title: 'Dev 文档已迁移',
-        description:
-            '/docs/dev/ 下的旧文档已下线,此 URL 对应的页面不再可用。请前往新版 Dev 文档继续浏览。',
-        linkLabel: '前往新版 Dev 文档',
-        linkTo: '/zh-CN/docs-next/dev/getting-started/what-is-apache-doris',
-    },
-};
-
-function detectLegacyDevLocale(pathname) {
-    if (!pathname) return null;
-    if (pathname === '/zh-CN/docs/dev' || 
pathname.startsWith('/zh-CN/docs/dev/')) {
-        return 'zh-CN';
-    }
-    if (pathname === '/docs/dev' || pathname.startsWith('/docs/dev/')) {
-        return 'en';
-    }
-    return null;
-}
-
-function LegacyDevGuidance({ locale }) {
-    const copy = LEGACY_DEV_GUIDANCE[locale];
-    return (
-        <main className="container margin-vert--xl">
-            <div className="row">
-                <div className="col">
-                    <div className="flex justify-center mb-10">
-                        <img
-                            style={{ width: 120 }}
-                            
src={require('@site/static/images/empty-data.png').default}
-                            alt=""
-                        />
-                    </div>
-                    <h1 className="text-[1.75rem] text-[#1D1D1D] leading-[1.6] 
text-center">
-                        {copy.title}
-                    </h1>
-                    <p className="text-center mt-2 text-sm text-[#8592A6]">
-                        {copy.description}
-                    </p>
-                    <div className="flex justify-center gap-x-6 lg:gap-x-10 
mt-10">
-                        <div className="w-[12.5rem]">
-                            <ExternalLink
-                                to={copy.linkTo}
-                                label={copy.linkLabel}
-                                className="text-sm h-[2.625rem] bg-primary 
text-white rounded-md hover:text-white cursor-pointer"
-                                linkIcon={<ExternalLinkArrowIcon />}
-                            />
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </main>
-    );
-}
-
-export default function NotFound() {
-    const [legacyDevLocale, setLegacyDevLocale] = useState(null);
-
-    useEffect(() => {
-        if (typeof window !== 'undefined') {
-            
setLegacyDevLocale(detectLegacyDevLocale(window.location.pathname));
-        }
-    }, []);
-
-    return (
-        <>
-            <PageMetadata
-                title={translate({
-                    id: 'theme.NotFound.title',
-                    message: 'Page Not Found',
-                })}
-            />
-            <Layout>
-                {legacyDevLocale ? (
-                    <LegacyDevGuidance locale={legacyDevLocale} />
-                ) : (
-                    <main className="container margin-vert--xl">
-                        <div className="row">
-                            <div className="col">
-                                <div className="flex justify-center mb-10">
-                                    <img
-                                        style={{ width: 120 }}
-                                        
src={require('@site/static/images/empty-data.png').default}
-                                        alt=""
-                                    />
-                                </div>
-                                <h1 className="text-[1.75rem] text-[#1D1D1D] 
leading-[1.6] text-center">
-                                    <Translate id="theme.NotFound.title" 
description="The title of the 404 page">
-                                        Page Not Found
-                                    </Translate>
-                                </h1>
-                                <p className="text-center mt-2 text-sm 
text-[#8592A6]">
-                                    <Translate id="theme.NotFound.p1" 
description="The first paragraph of the 404 page">
-                                        Oops! The page you are looking for 
can't be found. In any case, try to look for a
-                                        different page or report this issue.
-                                    </Translate>
-                                </p>
-                                <div className="flex justify-center gap-x-6 
lg:gap-x-10 mt-10">
-                                    <div className="w-[9.75rem]">
-                                        <ExternalLink
-                                            to="/"
-                                            label="Go to home"
-                                            className="text-sm h-[2.625rem] 
bg-primary text-white rounded-md hover:text-white cursor-pointer"
-                                            linkIcon={<ExternalLinkArrowIcon 
/>}
-                                        />
-                                    </div>
-                                    <div className="w-[9.75rem]">
-                                        <ExternalLink
-                                            label="Report this issue"
-                                            linkIcon={<ExternalLinkArrowIcon 
/>}
-                                            
to="https://github.com/apache/doris-website/issues";
-                                            className="text-sm border 
border-primary h-[2.625rem] rounded-md text-primary cursor-pointer"
-                                        />
-                                    </div>
-                                </div>
-                            </div>
-                        </div>
-                    </main>
-                )}
-            </Layout>
-        </>
-    );
-}
diff --git a/src/theme/NotFound/Content/index.js 
b/src/theme/NotFound/Content/index.js
new file mode 100644
index 00000000000..bcda25a7a71
--- /dev/null
+++ b/src/theme/NotFound/Content/index.js
@@ -0,0 +1,118 @@
+import React, { useEffect, useState } from 'react';
+import Translate from '@docusaurus/Translate';
+import ExternalLink from '@site/src/components/external-link/external-link';
+import { ExternalLinkArrowIcon } from 
'@site/src/components/Icons/external-link-arrow-icon';
+
+// Dev doc paths land here in two flavors:
+//   - legacy /docs/dev/* (and zh-CN counterpart) when no 1:1 redirect target
+//     was emitted by createRedirects;
+//   - new /docs-next/dev/* when DocRoot can't resolve the slug and falls back
+//     to NotFoundContent (bypassing the outer @theme/NotFound).
+// Both should land on a guidance card pointing at the new Dev docs entry.
+const DEV_GUIDANCE = {
+    en: {
+        title: 'This Dev doc has moved',
+        description:
+            'The page you requested is not available at this URL. The Dev docs 
now live under /docs-next/dev/.',
+        linkLabel: 'Go to new Dev docs',
+        linkTo: '/docs-next/dev/getting-started/what-is-apache-doris',
+    },
+    'zh-CN': {
+        title: 'Dev 文档已迁移',
+        description: '此 URL 对应的页面不再可用。新版 Dev 文档位于 /docs-next/dev/ 下。',
+        linkLabel: '前往新版 Dev 文档',
+        linkTo: '/zh-CN/docs-next/dev/getting-started/what-is-apache-doris',
+    },
+};
+
+function detectDevDocLocale(pathname) {
+    if (!pathname) return null;
+    if (/^\/zh-CN\/docs(-next)?\/dev(\/|$)/.test(pathname)) return 'zh-CN';
+    if (/^\/docs(-next)?\/dev(\/|$)/.test(pathname)) return 'en';
+    return null;
+}
+
+function DevDocGuidance({ locale }) {
+    const copy = DEV_GUIDANCE[locale];
+    return (
+        <>
+            <h1 className="text-[1.75rem] text-[#1D1D1D] leading-[1.6] 
text-center">
+                {copy.title}
+            </h1>
+            <p className="text-center mt-2 text-sm 
text-[#8592A6]">{copy.description}</p>
+            <div className="flex justify-center gap-x-6 lg:gap-x-10 mt-10">
+                <div className="w-[12.5rem]">
+                    <ExternalLink
+                        to={copy.linkTo}
+                        label={copy.linkLabel}
+                        className="text-sm h-[2.625rem] bg-primary text-white 
rounded-md hover:text-white cursor-pointer"
+                        linkIcon={<ExternalLinkArrowIcon />}
+                    />
+                </div>
+            </div>
+        </>
+    );
+}
+
+function GenericNotFound() {
+    return (
+        <>
+            <h1 className="text-[1.75rem] text-[#1D1D1D] leading-[1.6] 
text-center">
+                <Translate id="theme.NotFound.title" description="The title of 
the 404 page">
+                    Page Not Found
+                </Translate>
+            </h1>
+            <p className="text-center mt-2 text-sm text-[#8592A6]">
+                <Translate id="theme.NotFound.p1" description="The first 
paragraph of the 404 page">
+                    Oops! The page you are looking for can't be found. In any 
case, try to look for a
+                    different page or report this issue.
+                </Translate>
+            </p>
+            <div className="flex justify-center gap-x-6 lg:gap-x-10 mt-10">
+                <div className="w-[9.75rem]">
+                    <ExternalLink
+                        to="/"
+                        label="Go to home"
+                        className="text-sm h-[2.625rem] bg-primary text-white 
rounded-md hover:text-white cursor-pointer"
+                        linkIcon={<ExternalLinkArrowIcon />}
+                    />
+                </div>
+                <div className="w-[9.75rem]">
+                    <ExternalLink
+                        label="Report this issue"
+                        linkIcon={<ExternalLinkArrowIcon />}
+                        to="https://github.com/apache/doris-website/issues";
+                        className="text-sm border border-primary h-[2.625rem] 
rounded-md text-primary cursor-pointer"
+                    />
+                </div>
+            </div>
+        </>
+    );
+}
+
+export default function NotFoundContent({ className }) {
+    const [devLocale, setDevLocale] = useState(null);
+
+    useEffect(() => {
+        if (typeof window !== 'undefined') {
+            setDevLocale(detectDevDocLocale(window.location.pathname));
+        }
+    }, []);
+
+    return (
+        <main className={`container margin-vert--xl ${className || ''}`}>
+            <div className="row">
+                <div className="col">
+                    <div className="flex justify-center mb-10">
+                        <img
+                            style={{ width: 120 }}
+                            
src={require('@site/static/images/empty-data.png').default}
+                            alt=""
+                        />
+                    </div>
+                    {devLocale ? <DevDocGuidance locale={devLocale} /> : 
<GenericNotFound />}
+                </div>
+            </div>
+        </main>
+    );
+}
diff --git a/src/theme/NotFound/index.js b/src/theme/NotFound/index.js
new file mode 100644
index 00000000000..5e16b00d757
--- /dev/null
+++ b/src/theme/NotFound/index.js
@@ -0,0 +1,21 @@
+import React from 'react';
+import { translate } from '@docusaurus/Translate';
+import { PageMetadata } from '@docusaurus/theme-common';
+import Layout from '@theme/Layout';
+import NotFoundContent from '@theme/NotFound/Content';
+
+export default function NotFound() {
+    return (
+        <>
+            <PageMetadata
+                title={translate({
+                    id: 'theme.NotFound.title',
+                    message: 'Page Not Found',
+                })}
+            />
+            <Layout>
+                <NotFoundContent />
+            </Layout>
+        </>
+    );
+}
diff --git a/static/.htaccess b/static/.htaccess
index 2b98f7179eb..6ab39df5dbd 100644
--- a/static/.htaccess
+++ b/static/.htaccess
@@ -2,14 +2,25 @@
     Header set Content-Security-Policy "script-src 'self' 
https://cdnd.selectdb.com widget.kapa.ai www.google.com https://hcaptcha.com 
https://*.hcaptcha.com https://www.gstatic.com 'unsafe-inline' 'unsafe-eval'; 
connect-src 'self' proxy.kapa.ai kapa-widget-proxy-la7dkmplpq-uc.a.run.app 
metrics.kapa.ai https://hcaptcha.com https://*.hcaptcha.com www.google.com; 
frame-src 'self' www.google.com https://hcaptcha.com https://*.hcaptcha.com; 
worker-src 'self' https://cdnd.selectdb.com blob:;  [...]
 </IfModule>
 
-# Serve Docusaurus's built 404 page (which mounts src/theme/NotFound.js) for 
any
-# unknown URL, instead of httpd's default ErrorDocument. The browser keeps the
-# original path, so NotFound.js can detect legacy /docs/dev/* and show 
guidance.
-# For /zh-CN/* misses, rewrite to the zh-CN-locale 404 so the surrounding 
Layout
-# (header/footer/i18n context) renders in Chinese; the URL is preserved so the
-# React component still reads the original pathname for legacy detection.
+# Legacy /docs/dev/* paths whose 1:1 target was retired (renamed slugs, removed
+# pages) — server-side 301 to the new Dev docs landing. Doing it here avoids
+# the SPA hydration mismatch that results from /404.html being served on a
+# path the React router still treats as inside the docs prefix.
+# Paths emitted by createRedirects (1:1 matches) live on disk and short-circuit
+# via the -f check, so this only fires for genuinely missing slugs.
 <IfModule mod_rewrite.c>
     RewriteEngine On
+
+    RewriteCond %{REQUEST_FILENAME} !-f
+    RewriteCond %{REQUEST_FILENAME} !-d
+    RewriteRule ^docs/dev(/.*)?$ 
/docs-next/dev/getting-started/what-is-apache-doris [R=301,L]
+
+    RewriteCond %{REQUEST_FILENAME} !-f
+    RewriteCond %{REQUEST_FILENAME} !-d
+    RewriteRule ^zh-CN/docs/dev(/.*)?$ 
/zh-CN/docs-next/dev/getting-started/what-is-apache-doris [R=301,L]
+
+    # Other zh-CN misses — render the zh-CN-locale 404 so the chrome/i18n
+    # context (header/footer) is Chinese. URL is preserved.
     RewriteCond %{REQUEST_URI} ^/zh-CN/
     RewriteCond %{REQUEST_FILENAME} !-f
     RewriteCond %{REQUEST_FILENAME} !-d


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to