# สร้างแอปธนาคาร ตอนที่ 3: วิธีการดึงข้อมูลและใช้งานข้อมูล ลองนึกถึงคอมพิวเตอร์ของยาน Enterprise ใน Star Trek - เมื่อกัปตันพิคาร์ดถามสถานะของยาน ข้อมูลจะปรากฏขึ้นทันทีโดยที่อินเตอร์เฟซทั้งหมดไม่ต้องปิดลงและสร้างขึ้นใหม่ การไหลของข้อมูลที่ราบรื่นนี้คือสิ่งที่เรากำลังสร้างที่นี่ด้วยการดึงข้อมูลแบบไดนามิก ตอนนี้ แอปธนาคารของคุณเหมือนหนังสือพิมพ์ที่พิมพ์ออกมา - ให้ข้อมูลแต่ไม่เปลี่ยนแปลงได้ เรากำลังจะเปลี่ยนมันให้เหมือนกับศูนย์ควบคุมภารกิจของ NASA ซึ่งข้อมูลจะไหลอย่างต่อเนื่องและอัพเดตแบบเรียลไทม์โดยไม่ขัดจังหวะการทำงานของผู้ใช้ คุณจะได้เรียนรู้วิธีสื่อสารกับเซิร์ฟเวอร์แบบอะซิงโครนัส จัดการกับข้อมูลที่มาถึงในเวลาที่ต่างกัน และแปลงข้อมูลดิบให้กลายเป็นสิ่งที่มีความหมายสำหรับผู้ใช้ นี่คือความแตกต่างระหว่างเดโมกับซอฟต์แวร์ที่พร้อมใช้งานจริง ## ⚡ สิ่งที่คุณทำได้ใน 5 นาทีถัดไป **เส้นทางเริ่มต้นด่วนสำหรับนักพัฒนาที่มีเวลาไม่มาก** ```mermaid flowchart LR A[⚡ 5 นาที] --> B[ตั้งค่าเซิร์ฟเวอร์ API] B --> C[ทดสอบดึงข้อมูลด้วย curl] C --> D[สร้างฟังก์ชันเข้าสู่ระบบ] D --> E[ดูข้อมูลในแอ็กชัน] ``` - **นาทีที่ 1-2**: เริ่มเซิร์ฟเวอร์ API ของคุณ (`cd api && npm start`) และทดสอบการเชื่อมต่อ - **นาทีที่ 3**: สร้างฟังก์ชัน `getAccount()` พื้นฐานโดยใช้ fetch - **นาทีที่ 4**: เชื่อมต่อแบบฟอร์มเข้าสู่ระบบด้วย `action="javascript:login()"` - **นาทีที่ 5**: ทดสอบการเข้าสู่ระบบและดูข้อมูลแสดงในคอนโซล **คำสั่งทดสอบด่วน**: ```bash # ตรวจสอบว่า API กำลังทำงาน curl http://localhost:5000/api # ทดสอบการดึงข้อมูลบัญชี curl http://localhost:5000/api/accounts/test ``` **ทำไมสิ่งนี้ถึงสำคัญ**: ภายใน 5 นาที คุณจะเห็นเวทมนตร์ของการดึงข้อมูลแบบอะซิงโครนัสที่ขับเคลื่อนทุกแอปเว็บสมัยใหม่ นี่คือพื้นฐานที่ทำให้แอปรู้สึกตอบสนองและมีชีวิตชีวา ## 🗺️ การเดินทางเรียนรู้ของคุณผ่านแอปเว็บที่ขับเคลื่อนด้วยข้อมูล ```mermaid journey title จากหน้าเพจสแตติกสู่แอปพลิเคชันไดนามิก section การทำความเข้าใจกับวิวัฒนาการ การรีโหลดหน้าเพจแบบดั้งเดิม: 3: You ค้นพบประโยชน์ของ AJAX/SPA: 5: You เชี่ยวชาญรูปแบบ Fetch API: 7: You section การสร้างระบบตรวจสอบตัวตน สร้างฟังก์ชันล็อกอิน: 4: You จัดการกับการทำงานแบบอะซิงค์: 6: You จัดการเซสชันผู้ใช้: 8: You section การอัปเดต UI แบบไดนามิก เรียนรู้การจัดการ DOM: 5: You สร้างการแสดงผลธุรกรรม: 7: You สร้างแดชบอร์ดตอบสนอง: 9: You section รูปแบบมืออาชีพ การเรนเดอร์แบบเทมเพลต: 6: You กลยุทธ์จัดการข้อผิดพลาด: 7: You การเพิ่มประสิทธิภาพ: 8: You ``` **จุดหมายปลายทางของการเดินทาง**: เมื่อจบบทเรียนนี้ คุณจะเข้าใจว่าแอปเว็บสมัยใหม่ดึงข้อมูล ประมวลผล และแสดงข้อมูลแบบไดนามิกอย่างไร เพื่อสร้างประสบการณ์ผู้ใช้ที่ไหลลื่นตามที่เราเคยคาดหวังจากแอปมืออาชีพ ## แบบทดสอบก่อนเรียน [แบบทดสอบก่อนเรียน](https://ff-quizzes.netlify.app/web/quiz/45) ### สิ่งที่ต้องเตรียมก่อนเรียน ก่อนที่จะเริ่มดึงข้อมูล ให้แน่ใจว่าคุณได้เตรียมส่วนประกอบเหล่านี้ไว้แล้ว: - **บทเรียนก่อนหน้า**: ทำแบบฟอร์ม [เข้าสู่ระบบและลงทะเบียน](../2-forms/README.md) ให้สำเร็จก่อน - เราจะสร้างบนพื้นฐานนี้ - **เซิร์ฟเวอร์ในเครื่อง**: ติดตั้ง [Node.js](https://nodejs.org) และ [รันเซิร์ฟเวอร์ API](../api/README.md) เพื่อให้บริการข้อมูลบัญชี - **การเชื่อมต่อ API**: ทดสอบการเชื่อมต่อเซิร์ฟเวอร์ด้วยคำสั่งนี้: ```bash curl http://localhost:5000/api # การตอบสนองที่คาดไว้: "Bank API v1.0.0" ``` การทดสอบด่วนนี้ทำให้แน่ใจว่าส่วนประกอบทั้งหมดสื่อสารกันได้ดี: - ตรวจสอบว่า Node.js ทำงานถูกต้องบนระบบของคุณ - ยืนยันว่าเซิร์ฟเวอร์ API ของคุณใช้งานและตอบสนองอยู่ - ตรวจสอบว่าแอปของคุณสามารถเข้าถึงเซิร์ฟเวอร์ได้ (เหมือนเช็คสัญญาณวิทยุก่อนภารกิจ) ## 🧠 ภาพรวมระบบจัดการข้อมูล ```mermaid mindmap root((การจัดการข้อมูล)) Authentication Flow Login Process Form Validation Credential Verification Session Management User State Global Account Object Navigation Guards การจัดการข้อผิดพลาด API Communication Fetch Patterns GET Requests POST Requests การตอบกลับข้อผิดพลาด Data Formats การประมวลผล JSON การเข้ารหัส URL การแยกวิเคราะห์การตอบกลับ Dynamic UI Updates DOM Manipulation การอัปเดตข้อความอย่างปลอดภัย การสร้างองค์ประกอบ การคัดลอกแม่แบบ User Experience การอัปเดตแบบเรียลไทม์ ข้อความแสดงข้อผิดพลาด สถานะการโหลด Security Considerations XSS Prevention การใช้ textContent การทำความสะอาดข้อมูลนำเข้า การสร้าง HTML อย่างปลอดภัย CORS Handling คำขอข้ามต้นทาง การกำหนดค่าหัวข้อ การตั้งค่าสำหรับการพัฒนา ``` **หลักการสำคัญ**: แอปเว็บสมัยใหม่เป็นระบบประสานงานข้อมูล - พวกมันประสานงานระหว่างอินเตอร์เฟซผู้ใช้ เซิร์ฟเวอร์ API และโมเดลความปลอดภัยของเบราว์เซอร์ เพื่อสร้างประสบการณ์ที่ราบรื่นและตอบสนอง --- ## ทำความเข้าใจกับการดึงข้อมูลในแอปเว็บสมัยใหม่ วิธีที่แอปเว็บจัดการข้อมูลพัฒนาขึ้นอย่างมากในช่วงสองทศวรรษที่ผ่านมา การเข้าใจวิวัฒนาการนี้จะช่วยให้คุณเห็นว่าทำไมเทคนิคสมัยใหม่อย่าง AJAX และ Fetch API จึงทรงพลังและทำไมมันกลายเป็นเครื่องมือจำเป็นสำหรับนักพัฒนาเว็บ เรามาลองสำรวจว่าเว็บไซต์ดั้งเดิมทำงานอย่างไร และเปรียบเทียบกับแอปพลิเคชันไดนามิกที่ตอบสนองที่เราสร้างขึ้นในวันนี้ ### แอปหลายหน้าแบบดั้งเดิม (MPA) ในยุคแรกของเว็บ ทุกคลิกเหมือนเปลี่ยนช่องโทรทัศน์เก่า - หน้าจอจะว่างเปล่า แล้วค่อยๆ รับสัญญาณเนื้อหาใหม่ นี่คือความจริงของแอปเว็บสมัยแรกที่ทุกการโต้ตอบหมายถึงการสร้างเพจใหม่ทั้งหมดตั้งแต่ต้น ```mermaid sequenceDiagram participant User participant Browser participant Server User->>Browser: คลิกที่ลิงก์หรือส่งฟอร์ม Browser->>Server: ขอหน้า HTML ใหม่ Note over Browser: หน้าเพจกลายเป็นว่างเปล่า Server->>Browser: ส่งหน้าครบถ้วน HTML กลับ Browser->>User: แสดงหน้าผลใหม่ (กระพริบ/รีโหลด) ```  **ทำไมวิธีนี้รู้สึกเกะกะ:** - ทุกคลิกหมายถึงการสร้างหน้าใหม่ทั้งหมด - ผู้ใช้ถูกรบกวนขณะคิดโดยการกระพริบหน้าจอเหล่านั้น - การเชื่อมต่ออินเทอร์เน็ตทำงานหนักโดยดาวน์โหลดส่วนหัวและส่วนท้ายซ้ำๆ - แอปดูเหมือนการเปิดตู้เก็บเอกสารมากกว่าการใช้งานซอฟต์แวร์ ### แอปหน้าเดียวสมัยใหม่ (SPA) AJAX (Asynchronous JavaScript and XML) เปลี่ยนพาราไดม์นี้อย่างสิ้นเชิง เหมือนกับการออกแบบโมดูลาร์ของสถานีอวกาศนานาชาติ ซึ่งนักบินอวกาศสามารถเปลี่ยนส่วนประกอบรายตัวโดยไม่ต้องสร้างโครงสร้างทั้งหมดใหม่ AJAX อนุญาตให้เราอัพเดตส่วนใดส่วนหนึ่งของหน้าเว็บโดยไม่ต้องโหลดใหม่ทั้งหมด แม้ชื่อจะพูดถึง XML แต่วันนี้เรามักใช้ JSON เป็นหลัก แต่หลักการยังคงเหมือนเดิม: อัพเดตเฉพาะสิ่งที่ต้องเปลี่ยน ```mermaid sequenceDiagram participant User participant Browser participant JavaScript participant Server User->>Browser: โต้ตอบกับหน้าเพจ Browser->>JavaScript: เรียกตัวจัดการเหตุการณ์ JavaScript->>Server: ดึงข้อมูลที่จำเป็นเท่านั้น Server->>JavaScript: ส่งคืนข้อมูล JSON JavaScript->>Browser: อัปเดตองค์ประกอบหน้าเพจเฉพาะ Browser->>User: แสดงเนื้อหาที่อัปเดต (ไม่มีการโหลดใหม่) ```  **ทำไม SPA ถึงรู้สึกดีกว่า:** - แค่ส่วนที่เปลี่ยนจริงๆ เท่านั้นที่อัพเดต (เจ๋งใช่ไหม?) - ไม่มีการขัดจังหวะที่น่ารำคาญ - ผู้ใช้ยังคงอยู่กับงานของพวกเขา - ข้อมูลที่ส่งผ่านเครือข่ายน้อยกว่า ทำให้โหลดเร็วขึ้น - ทุกอย่างตอบสนองและรวดเร็วเหมือนแอปบนโทรศัพท์มือถือ ### วิวัฒนาการสู่ Fetch API สมัยใหม่ เบราว์เซอร์สมัยใหม่ให้ [`Fetch` API](https://developer.mozilla.org/docs/Web/API/Fetch_API) ซึ่งมาแทนที่ [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest) แบบเก่า เหมือนการเปลี่ยนจากการใช้เทเลกราฟมาใช้เมล Fetch API ใช้ promises เพื่อโค้ดอะซิงโครนัสที่สะอาดกว่าและรองรับ JSON อย่างเป็นธรรมชาติ | คุณลักษณะ | XMLHttpRequest | Fetch API | |---------|----------------|----------| | **ไวยากรณ์** | ซับซ้อน กำหนด callback | สะอาด ใช้ promise | | **การจัดการ JSON** | ต้องแยกแยะเอง | มีเมธอด `.json()` ในตัว | | **การจัดการข้อผิดพลาด** | ข้อมูลจำกัด | ข้อผิดพลาดครบถ้วน | | **รองรับสมัยใหม่** | เข้ากันได้กับรุ่นเก่า | Promise ES6+ และ async/await | > 💡 **ความเข้ากันได้ของเบราว์เซอร์**: ข่าวดี - Fetch API ทำงานได้ในทุกเบราว์เซอร์สมัยใหม่! ถ้าคุณสนใจเวอร์ชันเฉพาะ [caniuse.com](https://caniuse.com/fetch) มีข้อมูลครบถ้วน > **สรุป:** - ทำงานได้ดีใน Chrome, Firefox, Safari และ Edge (เกือบทุกที่ที่ผู้ใช้คุณใช้งาน) - แค่ Internet Explorer ต้องการความช่วยเหลือเพิ่มเติม (และถึงเวลาปล่อย IE ไปแล้ว) - เตรียมคุณให้พร้อมกับรูปแบบ async/await ที่เราจะใช้ต่อไป ### การใช้งานระบบเข้าสู่ระบบและดึงข้อมูล ตอนนี้เรามาเขียนระบบเข้าสู่ระบบที่แปลงแอปธนาคารของคุณจากการแสดงผลแบบนิ่งเป็นแอปที่ทำงานได้จริง เหมือนโปรโตคอลการยืนยันตัวตนที่ใช้ในสถานที่ทหารที่ปลอดภัย เราจะตรวจสอบข้อมูลผู้ใช้และให้สิทธิ์เข้าถึงข้อมูลเฉพาะบุคคล เราจะสร้างอย่างค่อยเป็นค่อยไป เริ่มจากการยืนยันตัวตนพื้นฐานแล้วเพิ่มฟังก์ชันการดึงข้อมูล #### ขั้นตอนที่ 1: สร้างฟังก์ชันเข้าสู่ระบบพื้นฐาน เปิดไฟล์ `app.js` ของคุณและเพิ่มฟังก์ชัน `login` ใหม่ ฟังก์ชันนี้จะจัดการกับกระบวนการยืนยันตัวผู้ใช้: ```javascript async function login() { const loginForm = document.getElementById('loginForm'); const user = loginForm.user.value; } ``` **มาลองแยกจุดนี้ดู:** - คำว่า `async` บอก JavaScript ว่า "เฮ้ ฟังก์ชันนี้อาจจะต้องรอบางอย่าง" - เรากำลังดึงแบบฟอร์มจากหน้า (ไม่ซับซ้อน แค่หาโดย ID) - แล้วดึงค่าชื่อผู้ใช้ที่ผู้ใช้พิมพ์เข้ามา - เคล็ดลับคือ: คุณสามารถเข้าถึงอินพุตในฟอร์มใดๆ โดยใช้คุณสมบัติ `name` ของมัน - ไม่จำเป็นต้องใช้ getElementById ซ้ำซ้อน! > 💡 **วิธีเข้าถึงฟอร์ม**: ทุกคอนโทรลในฟอร์มสามารถเข้าถึงโดยใช้ชื่อที่กำหนดไว้ใน HTML ด้วยแอตทริบิวต์ `name` ซึ่งทำให้การดึงข้อมูลสะอาดและอ่านง่าย #### ขั้นตอนที่ 2: สร้างฟังก์ชันดึงข้อมูลบัญชี หลังจากนั้น สร้างฟังก์ชันพิเศษเพื่อดึงข้อมูลบัญชีจากเซิร์ฟเวอร์ ตามแบบฟอร์มของฟังก์ชันลงทะเบียน แต่เน้นดึงข้อมูล: ```javascript async function getAccount(user) { try { const response = await fetch('//localhost:5000/api/accounts/' + encodeURIComponent(user)); return await response.json(); } catch (error) { return { error: error.message || 'Unknown error' }; } } ``` **โค้ดนี้ทำอะไรบ้าง:** - **ใช้** API `fetch` สมัยใหม่เพื่อขอข้อมูลแบบอะซิงโครนัส - **สร้าง** URL Request แบบ GET โดยมีพารามิเตอร์ชื่อผู้ใช้ - **ใช้** `encodeURIComponent()` เพื่อจัดการตัวอักษรพิเศษใน URL อย่างปลอดภัย - **แปลง** คำตอบเป็น JSON เพื่อจัดการข้อมูลง่ายขึ้น - **จัดการ** ข้อผิดพลาดโดยส่งคืนอ็อบเจ็กต์ข้อผิดพลาด แทนการล่มของโปรแกรม > ⚠️ **หมายเหตุความปลอดภัย**: ฟังก์ชัน `encodeURIComponent()` ใช้จัดการตัวอักษรพิเศษใน URL เช่นเดียวกับระบบเข้ารหัสในสื่อสารทางทะเล เพื่อให้ข้อความของคุณถึงปลายทางอย่างถูกต้อง ป้องกันตัวอักษรอย่าง "#" หรือ "&" ที่อาจทำให้ข้อมูลผิดพลาด > **เหตุผลที่สำคัญ:** - ป้องกันไม่ให้ตัวอักษรพิเศษทำลาย URL - ป้องกันการโจมตีด้วยการแก้ไข URL - ทำให้เซิร์ฟเวอร์ได้รับข้อมูลที่ถูกต้องตามต้องการ - ปฏิบัติตามแนวทางเขียนโปรแกรมที่ปลอดภัย #### เข้าใจการร้องขอ HTTP GET นี่อาจทำให้คุณแปลกใจ: เมื่อใช้ `fetch` โดยไม่เพิ่มออปชันใดๆ มันจะสร้างคำขอ [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET) โดยอัตโนมัติ เหมาะสมกับสิ่งที่เราทำ - ขอข้อมูลบัญชีผู้ใช้ คิดว่า GET เหมือนการขอยืมหนังสือจากห้องสมุดอย่างสุภาพ - ร้องขอดูข้อมูลที่มีอยู่แล้ว POST (ที่เราใช้สำหรับลงทะเบียน) เหมือนการส่งหนังสือใหม่เพิ่มลงในคอลเลกชัน | คำขอ GET | คำขอ POST | |-------------|-------------| | **วัตถุประสงค์** | ดึงข้อมูลที่มีอยู่ | ส่งข้อมูลใหม่ไปยังเซิร์ฟเวอร์ | | **พารามิเตอร์** | ใน URL หรือ query string | ในเนื้อหาของคำขอ | | **แคช** | สามารถแคชได้โดยเบราว์เซอร์ | โดยทั่วไปไม่แคช | | **ความปลอดภัย** | เปิดเผยใน URL และบันทึก | ซ่อนในเนื้อหาคำขอ | ```mermaid sequenceDiagram participant B as Browser participant S as Server Note over B,S: คำขอ GET (การดึงข้อมูล) B->>S: GET /api/accounts/test S-->>B: 200 OK + ข้อมูลบัญชี Note over B,S: คำขอ POST (การส่งข้อมูล) B->>S: POST /api/accounts + ข้อมูลบัญชีใหม่ S-->>B: 201 Created + การยืนยัน Note over B,S: การจัดการข้อผิดพลาด B->>S: GET /api/accounts/nonexistent S-->>B: 404 Not Found + ข้อความข้อผิดพลาด ``` #### ขั้นตอนที่ 3: รวมทุกอย่างเข้าด้วยกัน ตอนนี้ถึงเวลาส่วนที่น่าพอใจ - เชื่อมฟังก์ชันดึงข้อมูลบัญชีเข้ากับกระบวนการเข้าสู่ระบบ นี่คือจุดที่ทุกอย่างทำงานร่วมกัน: ```javascript async function login() { const loginForm = document.getElementById('loginForm'); const user = loginForm.user.value; const data = await getAccount(user); if (data.error) { return console.log('loginError', data.error); } account = data; navigate('/dashboard'); } ``` ฟังก์ชันนี้ทำตามลำดับชัดเจน: - ดึงชื่อผู้ใช้จากอินพุตฟอร์ม - ขอข้อมูลบัญชีของผู้ใช้จากเซิร์ฟเวอร์ - จัดการข้อผิดพลาดที่เกิดขึ้นระหว่างกระบวนการ - เก็บข้อมูลบัญชีและไปยังแดชบอร์ดเมื่อสำเร็จ > 🎯 **รูปแบบ Async/Await**: เนื่องจาก `getAccount` เป็นฟังก์ชันอะซิงโครนัส เราใช้คำสั่ง `await` เพื่อหยุดการทำงานจนกว่าเซิร์ฟเวอร์จะตอบกลับ ป้องกันโค้ดดำเนินต่อโดยใช้ข้อมูลที่ยังไม่ได้ #### ขั้นตอนที่ 4: สร้างที่เก็บข้อมูลของคุณ แอปของคุณต้องมีที่เก็บข้อมูลบัญชีไว้เมื่อโหลดข้อมูลแล้ว คิดว่านี่เป็นความทรงจำระยะสั้นของแอป - ที่ที่เก็บข้อมูลผู้ใช้ปัจจุบันให้พร้อมใช้งาน เพิ่มบรรทัดนี้ที่บนสุดของไฟล์ `app.js` ของคุณ: ```javascript // นี่เก็บข้อมูลบัญชีของผู้ใช้ปัจจุบัน let account = null; ``` **ทำไมเราต้องการแบบนี้:** - ทำให้ข้อมูลบัญชีเข้าถึงได้จากทุกที่ในแอป - เริ่มต้นด้วยค่า `null` หมายถึง “ยังไม่มีใครเข้าสู่ระบบ” - อัพเดตเมื่อมีใครเข้าสู่ระบบหรือสมัครสำเร็จ - ทำหน้าที่เป็นแหล่งข้อมูลเดียว - ไม่มีความสับสนว่าใครล็อกอินอยู่ #### ขั้นตอนที่ 5: เชื่อมแบบฟอร์มของคุณ ตอนนี้เชื่อมฟังก์ชันเข้าสู่ระบบใหม่กับแบบฟอร์ม HTML ของคุณ อัพเดตแท็กฟอร์มแบบนี้: ```html
``` **สิ่งที่การเปลี่ยนแปลงนี้ทำ:** - หยุดการทำงานเริ่มต้นของฟอร์มที่รีโหลดทั้งหน้า - เรียกฟังก์ชัน JavaScript ที่คุณเขียนแทน - รักษาความราบรื่นและเหมือนแอปหน้าเดียว - ให้คุณควบคุมได้เต็มที่เมื่อผู้ใช้กด "Login" #### ขั้นตอนที่ 6: เพิ่มประสิทธิภาพฟังก์ชันลงทะเบียนของคุณ เพื่อความสม่ำเสมอ อัพเดตฟังก์ชัน `register` ให้เก็บข้อมูลบัญชีและไปยังแดชบอร์ดด้วย: ```javascript // เพิ่มบรรทัดเหล่านี้ไว้ที่ท้ายฟังก์ชัน register ของคุณ account = result; navigate('/dashboard'); ``` **การปรับปรุงนี้ให้:** - **การเปลี่ยนผ่านอย่างราบรื่น** จากลงทะเบียนสู่แดชบอร์ด - **ประสบการณ์ผู้ใช้ที่สม่ำเสมอ** ระหว่างการเข้าสู่ระบบและลงทะเบียน - **เข้าถึงข้อมูลบัญชีทันที** หลังลงทะเบียนสำเร็จ #### ทดสอบการใช้งานของคุณ ```mermaid flowchart TD A[ผู้ใช้กรอกข้อมูลรับรอง] --> B[เรียกใช้ฟังก์ชันเข้าสู่ระบบ] B --> C[ดึงข้อมูลบัญชีจากเซิร์ฟเวอร์] C --> D{ได้รับข้อมูลสำเร็จหรือไม่?} D -->|ใช่| E[เก็บข้อมูลบัญชีไว้ทั่วทั้งระบบ] D -->|ไม่| F[แสดงข้อความข้อผิดพลาด] E --> G[นำทางไปยังแดชบอร์ด] F --> H[ผู้ใช้ยังคงอยู่ที่หน้าเข้าสู่ระบบ] ``` **เวลาลองใช้งาน:** 1. สร้างบัญชีใหม่เพื่อให้แน่ใจว่าทุกอย่างทำงาน 2. ลองเข้าสู่ระบบด้วยข้อมูลนั้น 3. ดูคอนโซลเบราว์เซอร์ (F12) ถ้ามีอะไรผิดปกติ 4. ตรวจสอบว่าคุณไปถึงแดชบอร์ดหลังเข้าสู่ระบบสำเร็จ ถ้ามีอะไรไม่ทำงาน ไม่ต้องตกใจ! ส่วนใหญ่แก้ไขง่าย เช่น พิมพ์ผิดหรือไม่ได้เปิดเซิร์ฟเวอร์ API #### คำอธิบายสั้นๆ เรื่อง Cross-Origin คุณอาจสงสัยว่า: "แอปเว็บฉันพูดคุยกับเซิร์ฟเวอร์ API ได้ยังไงในเมื่อมันรันต่างพอร์ตกัน?" คำถามดี! นี่คือสิ่งที่นักพัฒนาเว็บทุกคนเจอในสักวัน > 🔒 **ความปลอดภัยข้ามแหล่งที่มา**: เบราว์เซอร์บังคับใช้ "same-origin policy" เพื่อป้องกันการสื่อสารที่ไม่ได้รับอนุญาตระหว่างโดเมนต่างๆ เหมือนระบบตรวจสอบที่ Pentagon พวกเขาตรวจสอบว่าการสื่อสารได้รับอนุญาตก่อนอนุญาตให้ข้อมูลถูกส่ง > **ในระบบของเรา:** - แอปเว็บของคุณรันที่ `localhost:3000` (เซิร์ฟเวอร์พัฒนา) - เซิร์ฟเวอร์ API รันที่ `localhost:5000` (เซิร์ฟเวอร์แบ็กเอนด์) - เซิร์ฟเวอร์ API ใส่ [หัวข้อ CORS](https://developer.mozilla.org/docs/Web/HTTP/CORS) ที่อนุญาตการสื่อสารอย่างชัดเจนจากเว็บแอปของคุณ การตั้งค่านี้เหมือนกับการพัฒนาในโลกจริงที่แอปฟรอนต์เอนด์และแบ็กเอนด์มักรันบนเซิร์ฟเวอร์แยกกัน > 📚 **เรียนรู้เพิ่มเติม**: ดำดิ่งลึกใน API และการดึงข้อมูลด้วยบทเรียนครบถ้วนนี้จาก [Microsoft Learn โมดูล API](https://docs.microsoft.com/learn/modules/use-apis-discover-museum-art/?WT.mc_id=academic-77807-sagibbon) ## ส่งข้อมูลของคุณให้มีชีวิตใน HTML ตอนนี้เราจะทำให้ข้อมูลที่ดึงมาแสดงผลแก่ผู้ใช้ผ่านการจัดการ DOM เหมือนกระบวนการล้างรูปในห้องมืด เรากำลังเปลี่ยนข้อมูลที่มองไม่เห็นให้กลายเป็นสิ่งที่ผู้ใช้เห็นและสามารถโต้ตอบได้ การจัดการ DOM คือเทคนิคที่เปลี่ยนหน้าเว็บแบบสแตติกให้เป็นแอปพลิเคชันไดนามิกที่อัปเดตเนื้อหาตามปฏิสัมพันธ์ของผู้ใช้และการตอบสนองจากเซิร์ฟเวอร์ ### การเลือกเครื่องมือที่เหมาะสมกับงาน เมื่อพูดถึงการอัปเดต HTML ด้วย JavaScript คุณมีตัวเลือกหลายอย่าง คิดเหมือนกับเครื่องมือต่าง ๆ ในกล่องเครื่องมือ – แต่ละอันเหมาะสมกับงานเฉพาะอย่าง: | วิธี | ดีสำหรับอะไร | เมื่อไหร่ควรใช้ | ระดับความปลอดภัย | |--------|---------------------|----------------|--------------| | `textContent` | แสดงข้อมูลผู้ใช้อย่างปลอดภัย | ทุกครั้งที่แสดงข้อความ | ✅ แข็งแกร่งมั่นคง | | `createElement()` + `append()` | สร้างเลย์เอาต์ซับซ้อน | สร้างส่วนหรือรายการใหม่ | ✅ ปลอดภัยสุด ๆ | | `innerHTML` | ตั้งค่าเนื้อหา HTML | ⚠️ พยายามหลีกเลี่ยง | ❌ เสี่ยงสูง | #### วิธีปลอดภัยในการแสดงข้อความ: textContent คุณสมบัติ [`textContent`](https://developer.mozilla.org/docs/Web/API/Node/textContent) คือเพื่อนที่ดีที่สุดเมื่อแสดงข้อมูลผู้ใช้ มันเหมือนการมีบอดี้การ์ดให้เว็บเพจของคุณ – ไม่มีอะไรอันตรายผ่านเข้ามาได้: ```javascript // วิธีที่ปลอดภัยและน่าเชื่อถือในการอัปเดตข้อความ const balanceElement = document.getElementById('balance'); balanceElement.textContent = account.balance; ``` **ข้อดีของ textContent:** - ถือทุกอย่างเป็นข้อความธรรมดา (ป้องกันการรันสคริปต์) - ล้างเนื้อหาที่มีอยู่โดยอัตโนมัติ - มีประสิทธิภาพสำหรับการอัปเดตข้อความเรียบง่าย - มาพร้อมความปลอดภัยในตัวสำหรับเนื้อหาที่เป็นอันตราย #### การสร้างองค์ประกอบ HTML ไดนามิก สำหรับเนื้อหาที่ซับซ้อนมากขึ้น ให้ใช้ [`document.createElement()`](https://developer.mozilla.org/docs/Web/API/Document/createElement) ร่วมกับวิธี [`append()`](https://developer.mozilla.org/docs/Web/API/ParentNode/append): ```javascript // วิธีที่ปลอดภัยในการสร้างองค์ประกอบใหม่ const transactionItem = document.createElement('div'); transactionItem.className = 'transaction-item'; transactionItem.textContent = `${transaction.date}: ${transaction.description}`; container.append(transactionItem); ``` **เข้าใจวิธีนี้:** - **สร้าง** องค์ประกอบ DOM ใหม่ด้วยโปรแกรม - **ควบคุม** คุณสมบัติและเนื้อหาขององค์ประกอบอย่างเต็มที่ - **อนุญาต** โครงสร้างองค์ประกอบที่ซ้อนกันแบบซับซ้อน - **รักษา** ความปลอดภัยโดยการแยกโครงสร้างออกจากเนื้อหา > ⚠️ **ข้อควรระวังด้านความปลอดภัย**: ขณะที่ [`innerHTML`](https://developer.mozilla.org/docs/Web/API/Element/innerHTML) ปรากฏในบทเรียนจำนวนมาก แต่มันสามารถรันสคริปต์ที่ฝังมาได้ เหมือนกับระบบความปลอดภัยที่ CERN ที่ป้องกันการรันโค้ดไม่ได้รับอนุญาต การใช้ `textContent` และ `createElement` จึงเป็นทางเลือกที่ปลอดภัยกว่า > **ความเสี่ยงของ innerHTML:** - รันแท็ก `