如何修正部署網站或 App 後出現的 404 錯誤
如果你的 App 在本機運作正常,但部署後頁面卻回傳 404,最常見的原因是缺少單頁應用程式(SPA)的路由設定:伺服器去尋找一個名為 /dashboard 的檔案,但該檔案並不存在,因為這個路由只存在於 JavaScript 中。修正方法是加入一條後備規則,讓 App 路由回傳 index.html。其他原因包括建置輸出中缺少檔案、路徑區分大小寫、結尾斜線不一致、基礎路徑錯誤,以及從未部署的 API 路由。
首先,請確切記下是哪一個網址回傳 404,以及你是如何進到那裡的。錯誤的模式會直接指向原因。
步驟一:找出規律
| 你看到的現象 | 最可能的原因 | 前往 |
|---|---|---|
| 首頁正常,點擊連結也正常;但重新整理或直接開啟深層連結時出現 404 | 沒有 SPA 後備規則 | 步驟二 |
| 所有頁面都回傳 404,包括首頁 | 發佈了錯誤的資料夾,或建置沒有成功部署 | 步驟三 |
| 頁面能載入,但圖片、字型或腳本回傳 404 | 建置中缺少檔案,或路徑錯誤 | 步驟四 |
/about/ 正常,但 /about 失敗(或反過來) | 結尾斜線的處理方式 | 步驟五 |
/About 失敗,但 /about 正常 | 伺服器區分大小寫 | 步驟四 |
頁面能載入,但對 /api/... 的資料請求回傳 404 | API 未部署或未設定路由 | 步驟六 |
| 舊網站的網址回傳 404 | 缺少轉址設定 | 步驟七 |
| 只有在自訂網域上出現 | DNS 或網域設定 | 步驟八 |
要查看實際的狀態碼,請開啟開發者工具(右鍵 → 檢查),切換到 Network(網路)分頁,重新載入,然後查看第一個請求的狀態。
步驟二:加入 SPA 後備規則
這是最典型的情況。在 React、Vue 或 Svelte 的單頁應用程式中,伺服器實際上只有少數幾個真實檔案:index.html,以及一些 JavaScript 和 CSS。像 /dashboard 或 /projects/42 這樣的路由,是由瀏覽器中的路由器處理的。
- 點擊連結可以正常運作:路由器會改變網址,並在不向伺服器請求的情況下繪製新頁面。
- 重新整理或直接開啟連結會失敗:瀏覽器向伺服器請求
/dashboard,伺服器沒有這個檔案,於是回傳 404。
修正方法是加入一條規則:如果請求沒有對應到真實的檔案,就以 200 狀態碼回傳 index.html,交由路由器接手。具體做法取決於主機(請查閱你所使用主機目前的文件,因為細節會變動):
| 主機 | 典型的後備規則 |
|---|---|
| Netlify | 在發佈資料夾中放一個 _redirects 檔案,內容為 /* /index.html 200 |
| Vercel | 在 vercel.json 中設定 rewrite,將所有路徑導向 /index.html(框架預設值通常已會處理) |
| Cloudflare Pages | 當頂層沒有 404.html 時,預設提供 SPA 式的後備 |
| Nginx | 在 location / 區塊中加入 try_files $uri $uri/ /index.html; |
| Apache | 在 .htaccess 中加入 rewrite 規則,將非檔案請求導向 index.html |
| GitHub Pages | 沒有伺服器端 rewrite;常見的替代做法是使用 hash 路由,或使用會轉址的 404.html |
請確認這條規則不會吞掉真實的檔案:對 /assets/app.js 的請求仍必須回傳 JavaScript 檔案。如果它們改為回傳 index.html,你會看到空白頁面,並出現「Failed to load module script」錯誤。請參考修正空白白頁。
另外,請為路由器設定一個萬用路由(catch-all),讓不符合任何頁面的網址顯示友善的「找不到頁面」,而不是什麼都不顯示。
如果你無法變更伺服器設定,hash 路由(網址像 /#/dashboard)可以避開這個問題,因為 # 之後的部分永遠不會傳送到伺服器。這只是一種替代方案,而不是首選:網址較醜,對搜尋引擎也較不友善。
在伺服器端渲染或於建置時產生頁面的框架(Next.js、Astro 及類似框架),通常每個頁面都有真實的檔案或伺服器路由,因此這個問題在這些框架中比較少見。它們的對應情況是:某個頁面在建置時從未被產生。
步驟三:檢查實際部署了什麼
如果所有頁面都回傳 404,伺服器很可能沒有提供你建置好的 App。
- 正確的資料夾。 主機必須發佈建置輸出(Vite 通常是
dist,Create React App 是build,靜態 Next.js 匯出是out),而不是專案根目錄。 - 建置有執行。 閱讀部署記錄。如果建置失敗,主機可能根本沒有部署任何東西,或仍是舊版本。
index.html位於發佈資料夾的最上層,而不是在子資料夾中。- 基礎路徑相符。 如果 App 是由
example.com/app/提供服務,就必須以該基礎路徑建置(Vite 的base、React Router 的basename),否則每個路由與資產都會找不到。
步驟四:修正缺少的檔案與錯誤的路徑
當頁面能載入,但資產回傳 404 時:
- 大小寫敏感。 macOS 與 Windows 通常會把
Logo.png和logo.png視為同一個檔案,而大多數 Linux 伺服器則不會。請確保每個參照的檔名都與實際檔案完全相同。 - 建置之外的檔案。 在 Vite 中,
public/內的檔案會原樣複製,並以根路徑參照(/logo.png)。在程式碼中匯入的檔案則會被打包。放在專案其他位置的檔案,可能根本沒有被部署。 - 相對路徑。
images/photo.jpg會以目前的網址為基準解析,因此在/blog/post-1上會失效。請改用/images/photo.jpg。 - 上傳的檔案儲存在本機磁碟。 如果使用者上傳的檔案被寫入伺服器自己的資料夾,每次部署新版本時就會消失。請改用正式的檔案儲存服務。
步驟五:一致地處理結尾斜線
/about 與 /about/ 是不同的網址。各主機對於是否要加上或移除斜線的處理不同,如果與你的連結或路由器不一致,就可能產生 404 或重新導向迴圈。請選定一種風格,讓你的連結都使用該風格,並設定主機將另一種形式轉向到該風格。一致性也有助於搜尋引擎,否則它們可能會把每個頁面視為兩份。
步驟六:修正回傳 404 的 API 路由
如果頁面能載入,但 Network 分頁顯示 /api/... 的請求回傳 404:
- 後端未部署。 靜態主機只提供檔案;後端必須在某處執行。
- 正式環境中的路徑路由不同。 在開發時,代理伺服器可能把
/api轉發到另一個伺服器。在正式環境中,主機需要對等的 rewrite,或是前端必須直接呼叫 API 的真實位址。 - SPA 後備規則攔截了它。 如果某個 API 請求回傳
index.html並帶有 200 狀態碼,代表後備規則範圍太大。請將/api/*排除在外。
已發佈的 App 對 /api/orders 的請求回傳 404,但在預覽中卻能正常運作。請檢查預覽與已發佈的 App 中 /api 的路由方式,並讓已發佈的前端以相同的方式連到後端。
步驟七:轉址舊網址
如果你從另一個網站搬過來,或重新調整了結構,人們與搜尋引擎仍在使用的舊網址就會回傳 404。請為每個舊網址加上一個 301(永久)轉址,指向其新位置。請保留一份清單,並在上線後抽樣測試。我們的網站搬遷 WordPress 指南說明了如何建立這份清單。
步驟八:檢查網域
如果 App 在主機提供的位址上運作正常,但在你的自訂網域上回傳 404,可能是網域指向了錯誤的專案,或是主機尚未把該網域附加到你的網站上。請檢查 DNS 記錄與主機的網域設定。參考如何連接自訂網域。
讓你真正的 404 頁面發揮作用
有些 404 是正確的:只是有人輸入錯了網址。請讓該頁面對使用者有幫助:
- 一段簡短的訊息,以及通往首頁與重要區塊的連結
- 如果網站有搜尋功能,提供搜尋框
- 與網站其他部分相同的標頭與導覽列
在你的設定允許的情況下,對於不存在的頁面應回傳真正的 404 狀態碼。以 200 狀態碼回傳的「找不到」訊息,就是搜尋引擎所稱的軟 404,它會浪費抓取時間,並讓索引產生混亂。
常見錯誤
- 只靠點擊來測試。 務必把深層網址貼到新分頁中並重新整理來測試。
- 後備規則攔截一切。 資產與 API 路由回傳
index.html,導致空白頁面與令人困惑的 API 錯誤。 - 大小寫不一致,只在伺服器上才會出錯。
- 部署了原始碼資料夾,而不是建置輸出。
- 重新調整網址卻沒有設定轉址。 每個舊連結都會變成 404。
Mythex 中的 404
在 Mythex 中,你會從工作區發佈,而靜態前端會以靜態網站的形式部署。如果已發佈的頁面回傳 404,請提供代理人確切的網址、問題是在重新整理時出現還是在點擊時出現,以及 Network 分頁顯示的內容,並請它檢查路由設定。修正後請重新發佈,因為線上的 App 在你重新發佈之前只是一個快照。如果你最近才修改過專案,但線上網站看起來仍是舊的,請重新發佈並強制重新整理。如果建置失敗,可使用發佈對話框中的 Fix with AI 按鈕。相關說明請參考文件中的如何發佈與發佈疑難排解,也可以參考我們的除錯 AI 建置 App 指南。
404 檢查清單
- 已確切記下哪些網址回傳 404,以及是在點擊時、重新整理時,還是兩者都會
- SPA 後備規則為 App 路由回傳
index.html,並帶有 200 狀態碼 - 後備規則排除了真實檔案與
/api/* - 路由器有一個萬用的「找不到」路由
- 已發佈的是建置輸出資料夾,且建置成功
- 基礎路徑與 App 的提供位置相符
- 每個參照的檔名大小寫都與實際檔案相符
- 資產路徑以
/開頭 - 結尾斜線的風格一致
- API 路由已在正式環境中部署並設定路由
- 舊網址已設定 301 轉址
- 已把深層連結貼到新分頁中測試過
常見問題
為什麼我的 React App 在重新整理頁面時會出現 404?
在單頁應用程式中,像 /dashboard 這樣的路由只存在於 JavaScript 中。點擊連結之所以正常,是因為路由器在瀏覽器中處理了它;但重新整理時,瀏覽器會向伺服器要求一個並不存在的 /dashboard 檔案。修正方法是加入一條後備規則,讓 App 路由都回傳 index.html。
如何在 Netlify、Vercel 或 Nginx 上加入 SPA 後備規則?
在 Netlify 上,新增一個 _redirects 檔案,內容為 /* /index.html 200。在 Vercel 上,於 vercel.json 中加入 rewrite,將所有路徑導向 /index.html。在 Nginx 上,於 location 區塊中使用 try_files $uri $uri/ /index.html;。由於規則會變動,請查閱你所使用的主機的文件。
部署後我的圖片或檔案出現 404,為什麼?
通常是因為檔案不在建置輸出中、路徑的大小寫不符(伺服器通常區分大小寫,而你的筆電可能不區分),或是路徑應該以斜線開頭卻使用了相對路徑。
找不到的頁面應該回傳真正的 404 狀態碼嗎?
應該。請提供有幫助的找不到頁面,並在你的設定允許的情況下使用 404 狀態碼。搜尋引擎會把以 200 狀態碼回傳的「找不到」訊息視為軟 404,這會浪費抓取時間,也可能讓索引出現混亂。