วิธีแก้ error 404 หลังดีพลอยเว็บไซต์หรือแอป
หากแอปทำงานได้ในเครื่องแต่หน้าขึ้น 404 หลังดีพลอย สาเหตุที่พบบ่อยที่สุดคือไม่มีการจัดการ routing แบบ single-page app (SPA): เซิร์ฟเวอร์กำลังหาไฟล์ที่ชื่อ /dashboard ซึ่งไม่มีอยู่จริง เพราะ route นั้นมีอยู่เฉพาะใน JavaScript วิธีแก้คือกฎ fallback ที่ส่ง index.html สำหรับ route ของแอป สาเหตุอื่น ๆ ได้แก่ ไฟล์ที่หายไปจากผลลัพธ์ของการบิลด์ เส้นทางที่แยกตัวพิมพ์ ความต่างของ trailing slash base path ที่ผิด และ API route ที่ไม่เคยถูกดีพลอย
เริ่มจากการบันทึกว่า URL ไหนที่ขึ้น 404 และคุณไปถึงมันได้อย่างไร รูปแบบจะชี้ไปยังสาเหตุได้ทันที
ขั้นที่ 1: หารูปแบบ
| สิ่งที่คุณเห็น | สาเหตุที่น่าจะเป็น | ไปที่ |
|---|---|---|
| หน้าแรกใช้ได้ คลิกลิงก์ได้ แต่ รีเฟรช หรือเปิดลิงก์ลึกแล้วได้ 404 | ไม่มี SPA fallback | ขั้นที่ 2 |
| ทุกหน้า ขึ้น 404 รวมถึงหน้าแรก | โฟลเดอร์ผิดถูกเผยแพร่ หรือการบิลด์ไม่ได้ดีพลอย | ขั้นที่ 3 |
| หน้าโหลดได้ แต่ รูปภาพ ฟอนต์ หรือสคริปต์ ขึ้น 404 | ไฟล์หายจากการบิลด์ หรือเส้นทางผิด | ขั้นที่ 4 |
ทำงานกับ /about/ แต่ใช้ /about ไม่ได้ (หรือกลับกัน) | การจัดการ trailing slash | ขั้นที่ 5 |
/About ใช้ไม่ได้ แต่ /about ใช้ได้ | เซิร์ฟเวอร์แยกตัวพิมพ์ | ขั้นที่ 4 |
หน้าโหลดได้ แต่คำขอข้อมูลไปที่ /api/... ขึ้น 404 | API ยังไม่ได้ดีพลอยหรือไม่ได้ route | ขั้นที่ 6 |
| URL เก่าจากเว็บไซต์เดิมขึ้น 404 | ไม่มี redirect | ขั้นที่ 7 |
| ขึ้น 404 เฉพาะบนโดเมนของคุณเอง | DNS หรือการตั้งค่าโดเมน | ขั้นที่ 8 |
เพื่อดูสถานะ HTTP จริง ให้เปิดเครื่องมือสำหรับนักพัฒนา (คลิกขวา → Inspect) ไปที่แท็บ Network รีโหลด แล้วดูสถานะของคำขอแรก
ขั้นที่ 2: เพิ่ม SPA fallback
นี่คือกรณีคลาสสิก ในแอปแบบ single-page ของ React, Vue หรือ Svelte เซิร์ฟเวอร์มีไฟล์จริงเพียงไม่กี่ไฟล์: index.html และไฟล์ JavaScript กับ CSS บางไฟล์ route อย่าง /dashboard หรือ /projects/42 ถูกจัดการโดย router ในเบราว์เซอร์
- การคลิกลิงก์ ใช้ได้: router เปลี่ยน URL และวาดหน้าใหม่โดยไม่ต้องถามเซิร์ฟเวอร์
- การรีเฟรชหรือเปิดลิงก์โดยตรง ล้มเหลว: เบราว์เซอร์ขอ
/dashboardจากเซิร์ฟเวอร์ ซึ่งไม่มีไฟล์นั้น จึงตอบ 404
วิธีแก้คือกฎที่บอกว่า: ถ้าคำขอไม่ตรงกับไฟล์จริง ให้ส่ง index.html พร้อม status 200 แล้วปล่อยให้ router ทำงานต่อ วิธีเพิ่มขึ้นอยู่กับโฮสต์ (ตรวจเอกสารปัจจุบันของโฮสต์ เพราะรายละเอียดเปลี่ยนได้):
| โฮสต์ | กฎ fallback ที่ใช้บ่อย |
|---|---|
| Netlify | ไฟล์ _redirects ในโฟลเดอร์ที่เผยแพร่พร้อม /* /index.html 200 |
| Vercel | rewrite ใน vercel.json จากทุกเส้นทางไปยัง /index.html (เฟรมเวิร์กพรีเซ็ตมักจัดการให้) |
| Cloudflare Pages | ให้ fallback แบบ SPA เป็นค่าเริ่มต้นเมื่อไม่มี 404.html ระดับบนสุด |
| Nginx | try_files $uri $uri/ /index.html; ใน block location / |
| Apache | กฎ rewrite ใน .htaccess ที่ส่งคำขอที่ไม่ใช่ไฟล์ไปยัง index.html |
| GitHub Pages | ไม่มี rewrite ฝั่งเซิร์ฟเวอร์ วิธีแก้ที่ใช้กันคือ hash routing หรือ 404.html ที่ redirect |
ตรวจให้แน่ใจว่ากฎไม่ไปกลืนไฟล์จริง คำขอไปยัง /assets/app.js ต้องยังคงส่งไฟล์ JavaScript ถ้ามันส่ง index.html กลับมาแทน คุณจะได้หน้าว่างพร้อม error "Failed to load module script" ดูวิธีแก้หน้าขาวว่างเปล่า
นอกจากนี้ ให้ router มี catch-all route เพื่อให้ URL ที่ไม่ตรงกับหน้าใดแสดงหน้า "ไม่พบหน้า" ที่เป็นมิตรแทนที่จะไม่แสดงอะไรเลย
ถ้าคุณเปลี่ยนการตั้งค่าเซิร์ฟเวอร์ไม่ได้ hash routing (URL แบบ /#/dashboard) ช่วยหลีกเลี่ยงปัญหาได้ เพราะส่วนหลัง # ไม่เคยถูกส่งไปยังเซิร์ฟเวอร์ เป็นทางเลี่ยงไม่ใช่ทางเลือกแรก: URL ดูไม่สวยและเครื่องมือค้นหาเข้าใจได้ยากกว่า
เฟรมเวิร์กที่เรนเดอร์หน้าบนเซิร์ฟเวอร์หรือสร้างหน้าตอนบิลด์ (Next.js, Astro และอื่น ๆ) มักมีไฟล์จริงหรือ route ฝั่งเซิร์ฟเวอร์สำหรับแต่ละหน้า ปัญหานี้จึงพบน้อยกว่าที่นั่น สิ่งที่เทียบเท่าคือหน้าที่ไม่เคยถูกสร้างตอนบิลด์
ขั้นที่ 3: ตรวจว่าดีพลอยอะไรไปจริง
ถ้าทุกอย่างขึ้น 404 เซิร์ฟเวอร์น่าจะไม่ได้ให้บริการแอปที่บิลด์แล้วของคุณ
- โฟลเดอร์ที่ถูกต้อง โฮสต์ต้องเผยแพร่ผลลัพธ์ของการบิลด์ (ปกติคือ
distสำหรับ Vite,buildสำหรับ Create React App,outสำหรับ Next.js แบบ static export) ไม่ใช่รากของโปรเจกต์ - การบิลด์ทำงานจริง อ่านบันทึกการดีพลอย ถ้าการบิลด์ล้มเหลว โฮสต์อาจไม่ได้ดีพลอยอะไรเลย หรือยังคงเวอร์ชันเก่าอยู่
index.htmlอยู่ที่ระดับบนสุด ของโฟลเดอร์ที่เผยแพร่ ไม่ได้อยู่ในโฟลเดอร์ย่อย- base path ตรงกัน ถ้าแอปให้บริการที่
example.com/app/ต้องบิลด์ด้วย base นั้น (baseของ Vite,basenameของ React Router) ไม่เช่นนั้นทุก route และ asset จะหายหมด
ขั้นที่ 4: แก้ไฟล์ที่หายและเส้นทางที่ผิด
เมื่อหน้าโหลดได้แต่ asset ขึ้น 404:
- ตัวพิมพ์ใหญ่เล็ก macOS และ Windows มักถือว่า
Logo.pngกับlogo.pngเป็นไฟล์เดียวกัน แต่เซิร์ฟเวอร์ Linux ส่วนใหญ่ไม่ถือ ทำให้ทุกการอ้างอิงตรงกับชื่อไฟล์จริงทุกตัวอักษร - ไฟล์นอกการบิลด์ ใน Vite ไฟล์ในโฟลเดอร์
public/จะถูกคัดลอกตามเดิมและอ้างอิงจากรากเป็น/logo.pngไฟล์ที่ import ในโค้ดจะถูกรวมเข้าไปในบันเดิล ไฟล์ที่อยู่ที่อื่นในโปรเจกต์อาจไม่ถูกดีพลอยเลย - เส้นทางแบบ relative
images/photo.jpgจะถูกแปลจาก URL ปัจจุบัน จึงพังบน/blog/post-1ให้ใช้/images/photo.jpg - ไฟล์ที่อัปโหลดบันทึกลงดิสก์ในเครื่อง ถ้าไฟล์ของผู้ใช้ถูกเขียนลงโฟลเดอร์ของเซิร์ฟเวอร์ จะหายไปเมื่อดีพลอยเวอร์ชันใหม่ ให้ใช้สตอเรจไฟล์ที่เหมาะสม
ขั้นที่ 5: จัดการ trailing slash ให้สม่ำเสมอ
/about กับ /about/ เป็น URL ที่ต่างกัน โฮสต์แตกต่างกันในการเพิ่มหรือลบ slash และการไม่ตรงกับลิงก์หรือ router ของคุณอาจทำให้เกิด 404 หรือ redirect วนลูป เลือกรูปแบบเดียว ให้ลิงก์ของคุณใช้รูปแบบนั้น และตั้งค่าโฮสต์ให้ redirect อีกแบบมาที่รูปแบบนั้น ความสม่ำเสมอยังช่วยเครื่องมือค้นหาด้วย ไม่เช่นนั้นอาจเห็นหน้าเดียวกันสองชุดในแต่ละหน้า
ขั้นที่ 6: แก้ API route ที่ขึ้น 404
ถ้าหน้าโหลดได้แต่แท็บ Network แสดงคำขอ /api/... ที่ตอบ 404:
- ยังไม่ได้ดีพลอย back end โฮสต์แบบสแตติกให้บริการไฟล์เท่านั้น back end ต้องรันอยู่ที่ไหนสักแห่ง
- เส้นทางถูก route ต่างกันในโปรดักชัน ในการพัฒนา proxy อาจส่งต่อ
/apiไปยังเซิร์ฟเวอร์อีกตัว ในโปรดักชัน โฮสต์ต้องมี rewrite ที่เทียบเท่า หรือ frontend ต้องเรียกที่อยู่จริงของ API - กฎ SPA fallback จับคำขอ API ไว้ คำขอ API ที่ตอบด้วย
index.htmlพร้อม status 200 หมายความว่ากฎ fallback กว้างเกินไป ให้ยกเว้น/api/*ออกจากกฎ
คำขอของแอปที่เผยแพร่ไปยัง /api/orders ตอบ 404 แต่ใช้งานได้ในพรีวิว ตรวจว่า /api ถูก route ต่างกันระหว่างพรีวิวกับแอปที่เผยแพร่อย่างไร และทำให้ frontend ที่เผยแพร่เข้าถึง back end ด้วยวิธีเดียวกัน
ขั้นที่ 7: redirect URL เก่า
ถ้าคุณย้ายจากเว็บไซต์อื่นหรือจัดโครงสร้างใหม่ URL เก่าที่ผู้คนและเครื่องมือค้นหายังใช้อยู่จะขึ้น 404 เพิ่ม redirect แบบ 301 (ถาวร) จากแต่ละ URL เก่าไปยังที่ใหม่ เก็บรายการไว้และทดสอบตัวอย่างหลังเปิดตัว วิธีย้ายเว็บไซต์ WordPress ครอบคลุมการสร้างรายการนั้น
ขั้นที่ 8: ตรวจโดเมน
ถ้าแอปทำงานที่ที่อยู่ของโฮสต์ แต่ขึ้น 404 บนโดเมนของคุณเอง โดเมนอาจชี้ไปยังโปรเจกต์ผิด หรือโฮสต์ยังไม่ได้ผูกโดเมนกับไซต์ของคุณ ตรวจระเบียน DNS และการตั้งค่าโดเมนของโฮสต์ ดูวิธีเชื่อมต่อโดเมนของคุณเอง
ทำให้หน้า 404 จริงของคุณเป็นประโยชน์
404 บางครั้งถูกต้อง: มีคนพิมพ์ URL ผิด ทำให้หน้านั้นมีประโยชน์:
- ข้อความสั้น ๆ และลิงก์กลับไปหน้าแรกและส่วนสำคัญ
- กล่องค้นหา ถ้าเว็บไซต์มีการค้นหา
- ส่วนหัวและการนำทางเดียวกับหน้าอื่นของเว็บไซต์
ในที่ที่การตั้งค่าของคุณทำได้ ให้ส่ง status 404 จริงสำหรับหน้าที่ไม่มีอยู่ ข้อความ "ไม่พบ" ที่ส่งมาพร้อม status 200 คือสิ่งที่เครื่องมือค้นหาเรียกว่า soft 404 ซึ่งอาจเสียเวลาการคลานและทำให้การจัดทำดัชนีสับสน
ข้อผิดพลาดที่พบบ่อย
- ทดสอบแค่ด้วยการคลิก ให้ทดสอบเสมอโดยวาง URL ลึกลงในแท็บใหม่แล้วรีเฟรช
- fallback ที่จับทุกอย่าง ทำให้ asset และ API route ส่ง
index.htmlกลับมา ซึ่งทำให้หน้าว่างและ error ของ API สับสน - ตัวพิมพ์ใหญ่เล็กไม่ตรงกัน ที่พังเฉพาะบนเซิร์ฟเวอร์
- ดีพลอยโฟลเดอร์ซอร์ส แทนผลลัพธ์ของการบิลด์
- จัดโครงสร้าง URL ใหม่โดยไม่มี redirect ทุกลิงก์เดิมจะกลายเป็น 404
404 ใน Mythex
ใน Mythex คุณเผยแพร่จากพื้นที่ทำงาน และ front end แบบสแตติกถูกดีพลอยเป็นไซต์สแตติก ถ้าหน้าที่เผยแพร่ขึ้น 404 ให้บอกเอเจนต์ด้วย URL ที่แน่นอน ว่าเกิดขึ้นตอนรีเฟรชหรือตอนคลิก และแท็บ Network แสดงอะไร แล้วขอให้ตรวจ routing เผยแพร่อีกครั้งหลังแก้ไข เพราะแอปที่ใช้งานอยู่เป็นสแนปชอตจนกว่าคุณจะเผยแพร่ใหม่ ถ้าเพิ่งเปลี่ยนโปรเจกต์แล้วไซต์ที่ใช้งานอยู่ยังดูเก่า ให้เผยแพร่อีกครั้งและกด hard refresh ถ้าการบิลด์ล้มเหลว ให้ใช้ Fix with AI ในกล่องโต้ตอบการเผยแพร่ ดูHow to publish และ Publish troubleshooting ในเอกสาร และคู่มือของเรื่องการดีบักแอปที่สร้างด้วย AI
เช็กลิสต์ 404
- บันทึกแล้วว่า URL ไหนขึ้น 404 และเป็นตอนคลิก รีเฟรช หรือทั้งสองอย่าง
- SPA fallback ส่ง
index.htmlสำหรับ route ของแอป พร้อม status 200 - fallback ยกเว้นไฟล์จริงและ
/api/* - router มี route "ไม่พบ" แบบ catch-all
- โฟลเดอร์ผลลัพธ์ของการบิลด์คือสิ่งที่ถูกเผยแพร่ และการบิลด์สำเร็จ
- base path ตรงกับที่แอปถูกให้บริการ
- ตัวพิมพ์ของชื่อไฟล์ตรงกับทุกการอ้างอิง
- เส้นทางของ asset ขึ้นต้นด้วย
/ - รูปแบบ trailing slash สม่ำเสมอ
- API route ถูกดีพลอยและ route ในโปรดักชัน
- มี redirect 301 สำหรับ URL เก่า
- ทดสอบ deep link โดยวางลงในแท็บใหม่แล้ว
คำถาม
ทำไมรีเฟรชหน้าในแอป React แล้วขึ้น 404?
ในแอปแบบ single-page route อย่าง /dashboard มีอยู่เฉพาะใน JavaScript การคลิกลิงก์ใช้ได้เพราะ router จัดการในเบราว์เซอร์ แต่การรีเฟรชจะขอไฟล์ /dashboard จากเซิร์ฟเวอร์ ซึ่งไม่มีอยู่จริง วิธีแก้คือกฎ fallback ที่ส่ง index.html สำหรับ route ของแอป
จะเพิ่ม SPA fallback บน Netlify, Vercel หรือ Nginx อย่างไร?
บน Netlify เพิ่มไฟล์ _redirects พร้อมบรรทัด /* /index.html 200 บน Vercel เพิ่ม rewrite ใน vercel.json ที่ส่งทุกเส้นทางไปยัง /index.html บน Nginx ใช้ try_files $uri $uri/ /index.html; ใน location block ตรวจเอกสารของโฮสต์ของคุณเสมอ เพราะกฎอาจเปลี่ยนได้
ทำไมรูปภาพหรือไฟล์ของฉันขึ้น 404 หลังดีพลอย?
มักเกิดจากไฟล์ไม่อยู่ในผลลัพธ์ของการบิลด์ ตัวพิมพ์ใหญ่เล็กในเส้นทางไม่ตรงกัน (เซิร์ฟเวอร์มักแยกตัวพิมพ์ ขณะที่เครื่องของคุณอาจไม่แยก) หรือเส้นทางเป็นแบบ relative ทั้งที่ควรขึ้นต้นด้วยเครื่องหมายสแลช
หน้าที่ไม่มีอยู่ควรส่ง status 404 จริงหรือไม่?
ควรส่ง ให้แสดงหน้าไม่พบที่เป็นประโยชน์ แต่ใช้ status 404 ในที่ที่การตั้งค่าของคุณทำได้ เครื่องมือค้นหาจะมองว่าข้อความ "ไม่พบ" ที่ส่งมาพร้อม status 200 เป็น soft 404 ซึ่งเสียเวลาการคลาน (crawl) และอาจทำให้การจัดทำดัชนีสับสน