เกี่ยวกับ Codelab นี้
1 สิ่งที่คุณจะสร้าง
ใน Codelab นี้ คุณจะได้สร้างบล็อกท่องเที่ยวพร้อมแผนที่การทำงานร่วมกันแบบเรียลไทม์ โดยมี AngularFire เป็นเวอร์ชันล่าสุดจากไลบรารี Angular ของเรา เว็บแอปสุดท้ายจะประกอบด้วยบล็อกท่องเที่ยวซึ่งคุณสามารถอัปโหลดรูปภาพไปยังสถานที่แต่ละแห่งที่คุณเดินทางไปได้
ระบบจะใช้ AngularFire เพื่อสร้างเว็บแอป, ชุดโปรแกรมจำลองสำหรับการทดสอบในเครื่อง, การตรวจสอบสิทธิ์เพื่อติดตามข้อมูลผู้ใช้, Firestore และพื้นที่เก็บข้อมูลเพื่อคงข้อมูลและสื่อซึ่งขับเคลื่อนโดย Cloud Functions และสุดท้ายคือโฮสติ้งของ Firebase เพื่อทำให้แอปใช้งานได้
สิ่งที่คุณจะได้เรียนรู้
- วิธีพัฒนาด้วยผลิตภัณฑ์ Firebase ในเครื่องด้วยชุดโปรแกรมจำลอง
- วิธีเพิ่มประสิทธิภาพเว็บแอปด้วย AngularFire
- วิธีคงข้อมูลใน Firestore
- วิธีเก็บสื่อไว้ในพื้นที่เก็บข้อมูล
- วิธีทำให้แอปใช้งานได้กับโฮสติ้งของ Firebase
- วิธีใช้ Cloud Functions เพื่อโต้ตอบกับฐานข้อมูลและ API
สิ่งที่ต้องมี
- Node.js เวอร์ชัน 10 ขึ้นไป
- บัญชี Google สำหรับสร้างและจัดการโปรเจ็กต์ Firebase
- Firebase CLI เวอร์ชัน 11.14.2 ขึ้นไป
- เบราว์เซอร์ที่คุณเลือก เช่น Chrome
- ความเข้าใจพื้นฐานเกี่ยวกับ Angular และ JavaScript
2 รับโค้ดตัวอย่าง
โคลนที่เก็บ GitHub ของ Codelab จากบรรทัดคำสั่งดังนี้
git clone https://github.com/firebase/codelab-friendlychat-web
หรือหากยังไม่ได้ติดตั้ง Git ให้ดาวน์โหลดที่เก็บเป็นไฟล์ ZIP
ที่เก็บ GitHub มีโปรเจ็กต์ตัวอย่างสำหรับหลายแพลตฟอร์ม
Codelab นี้ใช้เฉพาะที่เก็บ WebFramework ต่อไปนี้
- 📁 webframework: โค้ดเริ่มต้นที่คุณจะสร้างขึ้นในระหว่าง Codelab นี้
ติดตั้งการอ้างอิง
หลังจากโคลนแล้ว ให้ติดตั้งทรัพยากร Dependency ในโฟลเดอร์รูทและ functions
ก่อนสร้างเว็บแอป
cd webframework && npm install
cd functions && npm install
ติดตั้ง Firebase CLI
ติดตั้ง Firebase CLI โดยใช้คำสั่งนี้ในเทอร์มินัล
npm install -g firebase-tools
ตรวจสอบอีกครั้งว่าเวอร์ชัน Firebase CLI ของคุณสูงกว่า 11.14.2 โดยใช้
firebase --version
หากเวอร์ชันต่ำกว่า 11.14.2 โปรดอัปเดตโดยใช้สิ่งต่อไปนี้
npm update firebase-tools
3 สร้างและตั้งค่าโปรเจ็กต์ Firebase
สร้างโปรเจ็กต์ Firebase
- ลงชื่อเข้าใช้ Firebase
- ในคอนโซล Firebase ให้คลิกเพิ่มโปรเจ็กต์ แล้วตั้งชื่อโปรเจ็กต์ Firebase ของคุณว่า <your-project> จำรหัสโปรเจ็กต์ของโปรเจ็กต์ Firebase
- คลิกสร้างโปรเจ็กต์
สำคัญ: ระบบจะตั้งชื่อโปรเจ็กต์ Firebase ว่า <your-project> แต่ Firebase จะกำหนดรหัสโปรเจ็กต์ที่ไม่ซ้ำให้โดยอัตโนมัติในรูปแบบ <your-project>-1234 ตัวระบุที่ไม่ซ้ำกันนี้คือวิธีระบุโปรเจ็กต์จริง (รวมถึงใน CLI) ขณะที่ <your-project> เป็นเพียงชื่อที่แสดง
แอปพลิเคชันที่เราจะสร้างใช้ผลิตภัณฑ์ Firebase ที่พร้อมใช้งานสำหรับเว็บแอป
- การตรวจสอบสิทธิ์ของ Firebase เพื่อให้ผู้ใช้ลงชื่อเข้าใช้แอปได้ง่ายๆ
- Cloud Firestore เพื่อบันทึก Structured Data ในระบบคลาวด์และรับการแจ้งเตือนทันทีเมื่อข้อมูลมีการเปลี่ยนแปลง
- Cloud Storage for Firebase เพื่อบันทึกไฟล์ในระบบคลาวด์
- โฮสติ้งของ Firebase เพื่อโฮสต์และแสดงเนื้อหาของคุณ
- ฟังก์ชันเพื่อโต้ตอบกับ API ภายในและภายนอก
ผลิตภัณฑ์เหล่านี้บางรายการต้องมีการกำหนดค่าพิเศษหรือต้องเปิดใช้โดยใช้คอนโซล Firebase
เพิ่มเว็บแอป Firebase ลงในโปรเจ็กต์
- คลิกไอคอนเว็บเพื่อสร้างเว็บแอป Firebase ใหม่
- คุณจะเห็นออบเจ็กต์การกำหนดค่าในขั้นตอนถัดไป คัดลอกเนื้อหาของออบเจ็กต์นี้ลงในไฟล์
environments/environment.ts
เปิดใช้การตรวจสอบสิทธิ์การลงชื่อเข้าใช้สำหรับ Firebase ของ Google
หากต้องการอนุญาตให้ผู้ใช้ลงชื่อเข้าใช้เว็บแอปด้วยบัญชี Google เราจะใช้วิธีการลงชื่อเข้าใช้ Google
หากต้องการเปิดใช้การลงชื่อเข้าใช้ Google ให้ทำดังนี้
- ในคอนโซล Firebase ให้ค้นหาส่วนสร้างในแผงด้านซ้าย
- คลิกการตรวจสอบสิทธิ์ แล้วคลิกแท็บวิธีการลงชื่อเข้าใช้ (หรือคลิกที่นี่เพื่อไปยังแท็บนั้นโดยตรง)
- เปิดใช้ผู้ให้บริการการลงชื่อเข้าใช้ Google แล้วคลิกบันทึก
- ตั้งชื่อแอปที่เปิดเผยต่อสาธารณะเป็น <your-project-name> แล้วเลือกอีเมลสนับสนุนของโปรเจ็กต์จากเมนูแบบเลื่อนลง
เปิดใช้ Cloud Firestore
- ในส่วน Build ของคอนโซล Firebase ให้คลิก Firestore Database
- คลิกสร้างฐานข้อมูลในแผง Cloud Firestore
- ตั้งค่าตำแหน่งที่ใช้เก็บข้อมูล Cloud Firestore คุณจะปล่อยค่านี้เป็นค่าเริ่มต้นหรือเลือกภูมิภาคที่อยู่ใกล้ๆ ก็ได้
เปิดใช้ Cloud Storage
โดยเว็บแอปนี้ใช้ Cloud Storage for Firebase เพื่อจัดเก็บ อัปโหลด และแชร์รูปภาพ
- ในส่วนสร้างของคอนโซล Firebase ให้คลิกพื้นที่เก็บข้อมูล
- หากไม่มีปุ่มเริ่มต้นใช้งาน แสดงว่ามีพื้นที่เก็บข้อมูลระบบคลาวด์อยู่แล้ว
เปิดใช้อยู่แล้ว และคุณไม่จำเป็นต้องทำตามขั้นตอนด้านล่าง
- คลิกเริ่มต้นใช้งาน
- อ่านข้อจำกัดความรับผิดเกี่ยวกับกฎความปลอดภัยสำหรับโปรเจ็กต์ Firebase แล้วคลิกถัดไป
- ระบบจะเลือกตำแหน่ง Cloud Storage ล่วงหน้าด้วยภูมิภาคเดียวกับที่คุณเลือกสำหรับฐานข้อมูล Cloud Firestore คลิกเสร็จสิ้นเพื่อตั้งค่าให้เสร็จสมบูรณ์
เมื่อใช้กฎความปลอดภัยเริ่มต้น ผู้ใช้ที่ตรวจสอบสิทธิ์แล้วจะเขียนอะไรก็ได้ลงใน Cloud Storage เราจะทำให้พื้นที่เก็บข้อมูลปลอดภัยยิ่งขึ้นใน Codelab นี้
4 เชื่อมต่อกับโปรเจ็กต์ Firebase
อินเทอร์เฟซบรรทัดคำสั่ง (CLI) ของ Firebase ช่วยให้คุณใช้โฮสติ้งของ Firebase เพื่อแสดงเว็บแอปภายในเครื่อง รวมถึงทำให้เว็บแอปใช้งานได้ในโปรเจ็กต์ Firebase ได้
ตรวจสอบว่าบรรทัดคำสั่งกำลังเข้าถึงไดเรกทอรี webframework
ในเครื่องของแอป
เชื่อมต่อโค้ดเว็บแอปกับโปรเจ็กต์ Firebase ขั้นแรก ให้เข้าสู่ระบบ Firebase CLI ในบรรทัดคำสั่ง
firebase login
จากนั้นเรียกใช้คำสั่งต่อไปนี้เพื่อสร้างชื่อแทนโปรเจ็กต์ แทนที่ $YOUR_PROJECT_ID
ด้วยรหัสของโปรเจ็กต์ Firebase
firebase use $YOUR_PROJECT_ID
เพิ่ม AngularFire
หากต้องการเพิ่ม AngularFire ลงในแอป ให้เรียกใช้คำสั่ง
ng add @angular/fire
จากนั้นทำตามวิธีการในบรรทัดคำสั่ง แล้วเลือกฟีเจอร์ที่มีอยู่ในโปรเจ็กต์ Firebase
เริ่มต้น Firebase
หากต้องการเริ่มต้นโปรเจ็กต์ Firebase ให้เรียกใช้
firebase init
จากนั้นเลือกฟีเจอร์และโปรแกรมจำลองที่ใช้ในโปรเจ็กต์ Firebase ตามข้อความแจ้งของบรรทัดคำสั่ง
เริ่มโปรแกรมจำลอง
จากไดเรกทอรี webframework
ให้เรียกใช้คำสั่งต่อไปนี้เพื่อเริ่มต้นโปรแกรมจำลอง
firebase emulators:start
ในที่สุดแล้ว คุณควรจะเห็นผลลัพธ์แบบนี้:
$ firebase emulators:start
i emulators: Starting emulators: auth, functions, firestore, hosting, functions
i firestore: Firestore Emulator logging to firestore-debug.log
i hosting: Serving hosting files from: public
✔ hosting: Local server: http://localhost:5000
i ui: Emulator UI logging to ui-debug.log
i functions: Watching "/functions" for Cloud Functions...
✔ functions[updateMap]: firestore function initialized.
┌─────────────────────────────────────────────────────────────┐
│ ✔ All emulators ready! It is now safe to connect your app. │
│ i View Emulator UI at http://localhost:4000 │
└─────────────────────────────────────────────────────────────┘
┌────────────────┬────────────────┬─────────────────────────────────┐
│ Emulator │ Host:Port │ View in Emulator UI │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Authentication │ localhost:9099 │ http://localhost:4000/auth │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Functions │ localhost:5001 │ http://localhost:4000/functions │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Firestore │ localhost:8080 │ http://localhost:4000/firestore │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Hosting │ localhost:5000 │ n/a │
└────────────────┴────────────────┴─────────────────────────────────┘
Emulator Hub running at localhost:4400
Other reserved ports: 4500
Issues? Report them at https://github.com/firebase/firebase-tools/issues and attach the *-debug.log files.
เมื่อคุณเห็นข้อความ ✔All emulators ready!
แสดงว่าโปรแกรมจำลองพร้อมใช้งานแล้ว
คุณควรเห็น UI ของแอปการเดินทางที่ (ยัง) ใช้งานไม่ได้
มาเริ่มสร้างกันเลย!
5 เชื่อมต่อเว็บแอปกับโปรแกรมจำลอง
เมื่อดูจากตารางในบันทึกของโปรแกรมจำลอง โปรแกรมจำลอง Cloud Firestore กำลังฟังพอร์ต 8080 และโปรแกรมจำลองการตรวจสอบสิทธิ์กำลังฟังพอร์ต 9099
เปิด EmulatorUI
ไปที่ http://127.0.0.1:4000/ ในเว็บเบราว์เซอร์ คุณควรเห็น UI ของชุดโปรแกรมจำลอง
กำหนดเส้นทางแอปเพื่อใช้โปรแกรมจำลอง
ใน src/app/app.module.ts
ให้เพิ่มโค้ดต่อไปนี้ลงในรายการการนำเข้าของ AppModule
@NgModule({
declarations: [...],
imports: [
provideFirebaseApp(() => initializeApp(environment.firebase)),
provideAuth(() => {
const auth = getAuth();
if (location.hostname === 'localhost') {
connectAuthEmulator(auth, 'http://127.0.0.1:9099', { disableWarnings: true });
}
return auth;
}),
provideFirestore(() => {
const firestore = getFirestore();
if (location.hostname === 'localhost') {
connectFirestoreEmulator(firestore, '127.0.0.1', 8080);
}
return firestore;
}),
provideFunctions(() => {
const functions = getFunctions();
if (location.hostname === 'localhost') {
connectFunctionsEmulator(functions, '127.0.0.1', 5001);
}
return functions;
}),
provideStorage(() => {
const storage = getStorage();
if (location.hostname === 'localhost') {
connectStorageEmulator(storage, '127.0.0.1', 5001);
}
return storage;
}),
...
]
ตอนนี้แอปได้รับการกำหนดค่าให้ใช้โปรแกรมจำลองภายในเครื่องแล้ว ซึ่งช่วยให้ทำการทดสอบและพัฒนาได้ในเครื่อง
6 การเพิ่มการตรวจสอบสิทธิ์
เมื่อตั้งค่าโปรแกรมจำลองสำหรับแอปแล้ว เราก็สามารถเพิ่มฟีเจอร์การตรวจสอบสิทธิ์เพื่อให้ผู้ใช้แต่ละรายลงชื่อเข้าใช้ก่อนโพสต์ข้อความได้
ในการดำเนินการนี้ เราสามารถนำเข้าฟังก์ชัน signin
จาก AngularFire โดยตรง และติดตามสถานะการตรวจสอบสิทธิ์ของผู้ใช้ด้วยฟังก์ชัน authState
แก้ไขฟังก์ชันหน้าการเข้าสู่ระบบเพื่อให้หน้าตรวจสอบสถานะการตรวจสอบสิทธิ์ของผู้ใช้ขณะโหลด
กำลังแทรกการตรวจสอบสิทธิ์ AngularFire
ใน src/app/pages/login-page/login-page.component.ts
ให้นำเข้า Auth
จาก @angular/fire/auth
และแทรกลงใน LoginPageComponent
นอกจากนี้ยังนำเข้าผู้ให้บริการการตรวจสอบสิทธิ์อย่าง Google และฟังก์ชันอย่าง signin
, signout
จากแพ็กเกจเดียวกันได้โดยตรงและใช้ในแอปได้ด้วย
import { Auth, GoogleAuthProvider, signInWithPopup, signOut, user } from '@angular/fire/auth';
export class LoginPageComponent implements OnInit {
private auth: Auth = inject(Auth);
private provider = new GoogleAuthProvider();
user$ = user(this.auth);
constructor() {}
ngOnInit(): void {}
login() {
signInWithPopup(this.auth, this.provider).then((result) => {
const credential = GoogleAuthProvider.credentialFromResult(result);
return credential;
})
}
logout() {
signOut(this.auth).then(() => {
console.log('signed out');}).catch((error) => {
console.log('sign out error: ' + error);
})
}
}
ตอนนี้หน้าเข้าสู่ระบบใช้งานได้แล้ว ลองลงชื่อเข้าใช้และดูผลลัพธ์ในโปรแกรมจำลองการตรวจสอบสิทธิ์
7 กำลังกำหนดค่า Firestore
ในขั้นตอนนี้ คุณจะเพิ่มฟังก์ชันการโพสต์และอัปเดตบล็อกโพสต์การเดินทางที่เก็บไว้ใน Firestore
ฟังก์ชัน Firestore จะอยู่ในแพ็กเกจล่วงหน้าจาก AngularFire ซึ่งคล้ายกับการตรวจสอบสิทธิ์ เอกสารแต่ละรายการเป็นของคอลเล็กชัน และเอกสารแต่ละฉบับก็อาจมีคอลเล็กชันที่ซ้อนกันอยู่ได้ คุณต้องทราบpath
ของเอกสารใน Firestore เพื่อสร้างและอัปเดตบล็อกโพสต์การเดินทาง
การติดตั้งใช้งาน TravelService
เนื่องจากหน้าเว็บหลายหน้าจะต้องอ่านและอัปเดตเอกสาร Firestore ในเว็บแอป เราจึงใช้ฟังก์ชันใน src/app/services/travel.service.ts
ได้ เพื่อหลีกเลี่ยงการแทรกฟังก์ชัน AngularFire เดียวกันซ้ำๆ ทุกหน้า
เริ่มต้นด้วยการแทรก Auth
ซึ่งคล้ายกับขั้นตอนก่อนหน้า รวมถึง Firestore
ในบริการของเรา การกำหนดออบเจ็กต์ user$
ที่สังเกตได้ซึ่งรอฟังสถานะการตรวจสอบสิทธิ์ปัจจุบันก็มีประโยชน์เช่นกัน
import { doc, docData, DocumentReference, Firestore, getDoc, setDoc, updateDoc, collection, addDoc, deleteDoc, collectionData, Timestamp } from "@angular/fire/firestore";
export class TravelService {
firestore: Firestore = inject(Firestore);
auth: Auth = inject(Auth);
user$ = authState(this.auth).pipe(filter(user => user !== null), map(user => user!));
router: Router = inject(Router);
การเพิ่มโพสต์การเดินทาง
โพสต์เกี่ยวกับการเดินทางจะเป็นเอกสารที่เก็บไว้ใน Firestore และเนื่องจากเอกสารต้องอยู่ในคอลเล็กชัน คอลเล็กชันที่มีโพสต์เกี่ยวกับการเดินทางทั้งหมดจะมีชื่อว่า travels
ดังนั้น เส้นทางของการโพสต์การเดินทางจะเป็น travels/
เมื่อใช้ฟังก์ชัน addDoc
จาก AngularFire คุณจะแทรกออบเจ็กต์ในคอลเล็กชันได้โดยทำดังนี้
async addEmptyTravel(userId: String) {
...
addDoc(collection(this.firestore, 'travels'), travelData).then((travelRef) => {
collection(this.firestore, `travels/${travelRef.id}/stops`);
setDoc(travelRef, {... travelData, id: travelRef.id})
this.router.navigate(['edit', `${travelRef.id}`]);
return travelRef;
})
}
การอัปเดตและการลบข้อมูล
เมื่อใช้ uid ของการโพสต์การเดินทาง เราสามารถอนุมานเส้นทางของเอกสารที่เก็บไว้ใน Firestore ได้ ซึ่งจะอ่าน อัปเดต หรือลบได้โดยใช้ฟังก์ชัน updateFoc
และ deleteDoc
ของ AngularFire ดังนี้
async updateData(path: string, data: Partial<Travel | Stop>) {
await updateDoc(doc(this.firestore, path), data)
}
async deleteData(path: string) {
const ref = doc(this.firestore, path);
await deleteDoc(ref)
}
การอ่านข้อมูลเป็นแบบที่สังเกตได้
เนื่องจากโพสต์และป้ายจอดรถระหว่างทางสามารถแก้ไขได้หลังจากสร้าง การใช้ออบเจ็กต์เอกสารเป็นข้อมูลที่สังเกตได้จึงจะมีประโยชน์มากกว่าสำหรับการสมัครรับข้อมูลการเปลี่ยนแปลงที่เกิดขึ้น ฟังก์ชันนี้ให้บริการโดยฟังก์ชัน docData
และ collectionData
จาก @angular/fire/firestore
getDocData(path: string) {
return docData(doc(this.firestore, path), {idField: 'id'}) as Observable<Travel | Stop>
}
getCollectionData(path: string) {
return collectionData(collection(this.firestore, path), {idField: 'id'}) as Observable<Travel[] | Stop[]>
}
การเพิ่มจุดแวะพักในโพสต์เกี่ยวกับการเดินทาง
เมื่อตั้งค่าการดําเนินการโพสต์การเดินทางแล้ว ก็ถึงเวลาพิจารณาการหยุดพัก ซึ่งจะอยู่ในคอลเล็กชันย่อยของโพสต์การเดินทาง เช่น travels/
วิธีนี้แทบจะเหมือนกับการสร้างโพสต์ท่องเที่ยว ลองท้าทายตัวคุณเองให้ลองใช้ด้วยตัวเอง หรือดูวิธีการติดตั้งใช้งานด้านล่าง
async addStop(travelId: string) {
...
const ref = await addDoc(collection(this.firestore, `travels/${travelId}/stops`), stopData)
setDoc(ref, {...stopData, id: ref.id})
}
เยี่ยม ระบบใช้ฟังก์ชัน Firestore ในบริการ Travel แล้ว คุณจึงดูการทํางานจริงได้ในตอนนี้
การใช้ฟังก์ชัน Firestore ในแอป
ไปที่ src/app/pages/my-travels/my-travels.component.ts
และแทรก TravelService
เพื่อใช้ฟังก์ชัน
travelService = inject(TravelService);
travelsData$: Observable<Travel[]>;
stopsList$!: Observable<Stop[]>;
constructor() {
this.travelsData$ = this.travelService.getCollectionData(`travels`) as Observable<Travel[]>
}
มีการเรียกใช้ TravelService
ในเครื่องมือสร้างเพื่อรับอาร์เรย์ที่สังเกตได้ของการเดินทางทั้งหมด
ในกรณีที่ต้องการเฉพาะการเดินทางของผู้ใช้ปัจจุบัน ให้ใช้ฟังก์ชัน query
วิธีอื่นๆ ในการดูแลความปลอดภัย ได้แก่ การใช้กฎความปลอดภัย หรือการใช้ Cloud Functions กับ Firestore ตามที่ได้อธิบายไว้ในขั้นตอนที่ไม่บังคับด้านล่าง
จากนั้น เพียงเรียกใช้ฟังก์ชันที่ใช้งานใน TravelService
async createTravel(userId: String) {
this.travelService.addEmptyTravel(userId);
}
deleteTravel(travelId: String) {
this.travelService.deleteData(`travels/${travelId}`)
}
เท่านี้หน้า My Travels ก็น่าจะใช้งานได้แล้ว ดูว่าจะเกิดอะไรขึ้นในโปรแกรมจำลอง Firestore เมื่อคุณสร้างโพสต์การเดินทางใหม่
จากนั้น ทำซ้ำสำหรับฟังก์ชันอัปเดตใน /src/app/pages/edit-travels/edit-travels.component.ts
:
travelService: TravelService = inject(TravelService)
travelId = this.activatedRoute.snapshot.paramMap.get('travelId');
travelData$: Observable<Travel>;
stopsData$: Observable<Stop[]>;
constructor() {
this.travelData$ = this.travelService.getDocData(`travels/${this.travelId}`) as Observable<Travel>
this.stopsData$ = this.travelService.getCollectionData(`travels/${this.travelId}/stops`) as Observable<Stop[]>
}
updateCurrentTravel(travel: Partial<Travel>) {
this.travelService.updateData(`travels${this.travelId}`, travel)
}
updateCurrentStop(stop: Partial<Stop>) {
stop.type = stop.type?.toString();
this.travelService.updateData(`travels${this.travelId}/stops/${stop.id}`, stop)
}
addStop() {
if (!this.travelId) return;
this.travelService.addStop(this.travelId);
}
deleteStop(stopId: string) {
if (!this.travelId || !stopId) {
return;
}
this.travelService.deleteData(`travels${this.travelId}/stops/${stopId}`)
this.stopsData$ = this.travelService.getCollectionData(`travels${this.travelId}/stops`) as Observable<Stop[]>
}
8 กำลังกำหนดค่าพื้นที่เก็บข้อมูล
คราวนี้คุณจะใช้พื้นที่เก็บข้อมูลเพื่อเก็บรูปภาพและสื่อประเภทอื่นๆ
Cloud Firestore เหมาะสำหรับเก็บข้อมูลที่มีโครงสร้าง เช่น ออบเจ็กต์ JSON Cloud Storage ได้รับการออกแบบมาเพื่อจัดเก็บไฟล์หรือ Blob ในแอปนี้ คุณจะใช้แอปนั้นเพื่ออนุญาตให้ผู้ใช้แชร์รูปภาพการเดินทางได้
เช่นเดียวกับ Firestore การจัดเก็บและการอัปเดตไฟล์ด้วยพื้นที่เก็บข้อมูลจะต้องมีตัวระบุที่ไม่ซ้ำกันสำหรับแต่ละไฟล์
มาใช้ฟังก์ชันใน TraveService
กัน
การอัปโหลดไฟล์
ไปที่ src/app/services/travel.service.ts
และแทรก Storage จาก AngularFire:
export class TravelService {
firestore: Firestore = inject(Firestore);
auth: Auth = inject(Auth);
storage: Storage = inject(Storage);
และใช้ฟังก์ชันการอัปโหลดดังนี้
async uploadToStorage(path: string, input: HTMLInputElement, contentType: any) {
if (!input.files) return null
const files: FileList = input.files;
for (let i = 0; i < files.length; i++) {
const file = files.item(i);
if (file) {
const imagePath = `${path}/${file.name}`
const storageRef = ref(this.storage, imagePath);
await uploadBytesResumable(storageRef, file, contentType);
return await getDownloadURL(storageRef);
}
}
return null;
}
ความแตกต่างหลักระหว่างการเข้าถึงเอกสารจาก Firestore และไฟล์จาก Cloud Storage คือ แม้ว่าทั้ง 2 แบบจะติดตามเส้นทางที่มีโครงสร้างของโฟลเดอร์ แต่ระบบจะรับชุดค่าผสม URL พื้นฐานและเส้นทางผ่าน getDownloadURL
ซึ่งสามารถจัดเก็บและใช้ในไฟล์
ได้
การใช้ฟังก์ชันในแอป
ไปที่ src/app/components/edit-stop/edit-stop.component.ts
และเรียกฟังก์ชันอัปโหลดโดยใช้สิ่งต่อไปนี้
async uploadFile(file: HTMLInputElement, stop: Partial<Stop>) {
const path = `/travels/${this.travelId}/stops/${stop.id}`
const url = await this.travelService.uploadToStorage(path, file, {contentType: 'image/png'});
stop.image = url ? url : '';
this.travelService.updateData(path, stop);
}
เมื่ออัปโหลดรูปภาพแล้ว ระบบจะอัปโหลดไฟล์สื่อไปยังพื้นที่เก็บข้อมูล และ URL จะจัดเก็บไว้ในเอกสารใน Firestore
9 การทำให้แอปพลิเคชันใช้งานได้
ตอนนี้เราพร้อมแล้วที่จะทำให้แอปพลิเคชันใช้งานได้
คัดลอกการกำหนดค่า firebase
จาก src/environments/environment.ts
ไปยัง src/environments/environment.prod.ts
และเรียกใช้
firebase deploy
คุณควรจะเห็นบางสิ่งเช่นนี้:
✔ Browser application bundle generation complete.
✔ Copying assets complete.
✔ Index html generation complete.
=== Deploying to 'friendly-travels-b6a4b'...
i deploying storage, firestore, hosting
i firebase.storage: checking storage.rules for compilation errors...
✔ firebase.storage: rules file storage.rules compiled successfully
i firestore: reading indexes from firestore.indexes.json...
i cloud.firestore: checking firestore.rules for compilation errors...
✔ cloud.firestore: rules file firestore.rules compiled successfully
i storage: latest version of storage.rules already up to date, skipping upload...
i firestore: deploying indexes...
i firestore: latest version of firestore.rules already up to date, skipping upload...
✔ firestore: deployed indexes in firestore.indexes.json successfully for (default) database
i hosting[friendly-travels-b6a4b]: beginning deploy...
i hosting[friendly-travels-b6a4b]: found 6 files in .firebase/friendly-travels-b6a4b/hosting
✔ hosting[friendly-travels-b6a4b]: file upload complete
✔ storage: released rules storage.rules to firebase.storage
✔ firestore: released rules firestore.rules to cloud.firestore
i hosting[friendly-travels-b6a4b]: finalizing version...
✔ hosting[friendly-travels-b6a4b]: version finalized
i hosting[friendly-travels-b6a4b]: releasing new version...
✔ hosting[friendly-travels-b6a4b]: release complete
✔ Deploy complete!
Project Console: https://console.firebase.google.com/project/friendly-travels-b6a4b/overview
Hosting URL: https://friendly-travels-b6a4b.web.app
10 ยินดีด้วย
ตอนนี้แอปพลิเคชันของคุณควรจะเสร็จสมบูรณ์และใช้งานได้ในโฮสติ้งของ Firebase แล้ว ตอนนี้คุณจะเข้าถึงข้อมูลและการวิเคราะห์ทั้งหมดได้ในคอนโซล Firebase
สำหรับฟีเจอร์เพิ่มเติมเกี่ยวกับ AngularFire, ฟังก์ชัน, กฎความปลอดภัย โปรดอย่าลืมดูขั้นตอนทางเลือกด้านล่างนี้ รวมถึง Firebase Codelab อื่นๆ
11 ไม่บังคับ: ตัวป้องกันการตรวจสอบสิทธิ์ AngularFire
AngularFire ควบคู่กับการตรวจสอบสิทธิ์ Firebase แล้วยังมีการป้องกันที่อิงตามการตรวจสอบสิทธิ์บนเส้นทาง เพื่อให้ระบบเปลี่ยนเส้นทางผู้ใช้ที่มีสิทธิ์เข้าถึงไม่เพียงพอได้ วิธีนี้จะช่วยปกป้องแอปจากผู้ใช้ที่เข้าถึงข้อมูลที่มีการป้องกัน
ใน src/app/app-routing.module.ts
ให้นำเข้า
import {AuthGuard, redirectLoggedInTo, redirectUnauthorizedTo} from '@angular/fire/auth-guard'
จากนั้นคุณสามารถกำหนดฟังก์ชันว่าเมื่อใดและควรเปลี่ยนเส้นทางผู้ใช้ไปที่ใดในหน้าบางหน้า ดังนี้
const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(['signin']);
const redirectLoggedInToTravels = () => redirectLoggedInTo(['my-travels']);
จากนั้นเพียงเพิ่มลงในเส้นทางของคุณ:
const routes: Routes = [
{path: '', component: LoginPageComponent, canActivate: [AuthGuard], data: {authGuardPipe: redirectLoggedInToTravels}},
{path: 'signin', component: LoginPageComponent, canActivate: [AuthGuard], data: {authGuardPipe: redirectLoggedInToTravels}},
{path: 'my-travels', component: MyTravelsComponent, canActivate: [AuthGuard], data: {authGuardPipe: redirectUnauthorizedToLogin}},
{path: 'edit/:travelId', component: EditTravelsComponent, canActivate: [AuthGuard], data: {authGuardPipe: redirectUnauthorizedToLogin}},
];
12 ไม่บังคับ: กฎความปลอดภัย
ทั้ง Firestore และ Cloud Storage จะใช้กฎความปลอดภัย (firestore.rules
และ security.rules
ตามลำดับ) เพื่อบังคับใช้ความปลอดภัยและตรวจสอบข้อมูล
ขณะนี้ใน Firestore และพื้นที่เก็บข้อมูลมีสิทธิ์แบบเปิดสำหรับอ่านและเขียน แต่คุณไม่ต้องการให้ผู้อื่นเปลี่ยนแปลง โพสต์ คุณจะใช้กฎความปลอดภัยเพื่อจำกัดการเข้าถึงคอลเล็กชันและเอกสารได้
กฎ Firestore
หากต้องการอนุญาตให้ผู้ใช้ที่ผ่านการตรวจสอบสิทธิ์แล้วเท่านั้นจึงจะดูโพสต์การเดินทางได้ ให้ไปที่ไฟล์ firestore.rules
แล้วเพิ่มรายการต่อไปนี้
rules_version = '2';
service cloud.firestore {
match /databases/{database}/travels {
allow read: if request.auth.uid != null;
allow write:
if request.auth.uid == request.resource.data.userId;
}
}
นอกจากนี้ยังใช้กฎความปลอดภัยเพื่อตรวจสอบข้อมูลได้ด้วย ดังนี้
rules_version = '2';
service cloud.firestore {
match /databases/{database}/posts {
allow read: if request.auth.uid != null;
allow write:
if request.auth.uid == request.resource.data.userId;
&& "author" in request.resource.data
&& "text" in request.resource.data
&& "timestamp" in request.resource.data;
}
}
กฎพื้นที่เก็บข้อมูล
ในทำนองเดียวกัน เราสามารถใช้กฎความปลอดภัยเพื่อบังคับใช้การเข้าถึงฐานข้อมูลพื้นที่เก็บข้อมูลใน storage.rules
โปรดทราบว่าเรายังใช้ฟังก์ชันสำหรับการตรวจสอบที่ซับซ้อนขึ้นได้ด้วย ดังนี้
rules_version = '2';
function isImageBelowMaxSize(maxSizeMB) {
return request.resource.size < maxSizeMB * 1024 * 1024
&& request.resource.contentType.matches('image/.*');
}
service firebase.storage {
match /b/{bucket}/o {
match /{userId}/{postId}/{filename} {
allow write: if request.auth != null
&& request.auth.uid == userId && isImageBelowMaxSize(5);
allow read;
}
}
}