Menangani sesi dengan Firestore

Tutorial ini menunjukkan cara menangani sesi di Cloud Run.

Banyak aplikasi memerlukan penanganan sesi untuk autentikasi dan preferensi pengguna. Paket Gorilla Web Toolkit sessions dilengkapi dengan penerapan berbasis sistem file untuk menjalankan fungsi ini. Namun, penerapan ini tidak cocok untuk aplikasi yang dapat ditayangkan dari beberapa instance, karena sesi yang direkam dalam satu instance mungkin berbeda dengan instance lainnya. Paket gorilla/sessions juga dilengkapi dengan penerapan berbasis cookie. Namun, penerapan ini memerlukan enkripsi cookie dan penyimpanan seluruh sesi di klien, bukan hanya ID sesi, yang mungkin terlalu besar untuk beberapa aplikasi.

Tujuan

  • Tulis aplikasi.
  • Jalankan aplikasi secara lokal.
  • Deploy aplikasi di Cloud Run.

Biaya

Dalam dokumen ini, Anda akan menggunakan komponen Google Cloudyang dapat ditagih berikut:

Untuk membuat perkiraan biaya berdasarkan proyeksi penggunaan Anda, gunakan kalkulator harga.

Pengguna Google Cloud baru mungkin memenuhi syarat untuk mendapatkan uji coba gratis.

Setelah menyelesaikan tugas yang dijelaskan dalam dokumen ini, Anda dapat menghindari penagihan berkelanjutan dengan menghapus resource yang Anda buat. Untuk mengetahui informasi selengkapnya, lihat Pembersihan.

Sebelum memulai

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. Enable the Firestore API.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the API

  5. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  6. Verify that billing is enabled for your Google Cloud project.

  7. Enable the Firestore API.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the API

  8. Di konsol Google Cloud , buka aplikasi di Cloud Shell.

    Buka Cloud Shell

    Cloud Shell menyediakan akses command line ke resource cloud Anda langsung dari browser. Buka Cloud Shell di browser Anda dan klik Proceed untuk mendownload kode contoh dan beralih ke direktori aplikasi.

  9. Di Cloud Shell, konfigurasikan gcloud CLI untuk menggunakan project Google Cloud baru Anda:
    # Configure gcloud for your project
    gcloud config set project YOUR_PROJECT_ID
    

Menyiapkan project

  1. Di jendela terminal, clone repositori aplikasi contoh ke komputer lokal Anda:

    git clone https://github.com/GoogleCloudPlatform/golang-samples.git
  2. Ubah ke direktori yang berisi kode contoh:

    cd golang-samples/getting-started/sessions

Memahami aplikasi web

Aplikasi ini menampilkan sapaan dalam berbagai bahasa untuk setiap pengguna. Pengguna yang kembali selalu disapa dalam bahasa yang sama.

Beberapa jendela aplikasi menampilkan ucapan dalam berbagai bahasa.

Sebelum aplikasi dapat menyimpan preferensi untuk pengguna, Anda memerlukan cara untuk menyimpan informasi tentang pengguna saat ini dalam sesi. Aplikasi contoh ini menggunakan Firestore untuk menyimpan data sesi.

  1. Aplikasi dimulai dengan mengimpor dependensi, menentukan jenis app untuk menyimpan sessions.Store dan template HTML, serta menentukan daftar ucapan.

    import (
    	"context"
    	"html/template"
    	"log"
    	"math/rand"
    	"net/http"
    	"os"
    
    	"cloud.google.com/go/firestore"
    )
    
    // app stores a sessions.Store. Create a new app with newApp.
    type app struct {
    	tmpl         *template.Template
    	collectionID string
    	projectID    string
    }
    
    // session stores the client's session information.
    // This type is also used for executing the template.
    type session struct {
    	Greetings string `json:"greeting"`
    	Views     int    `json:"views"`
    }
    
    // greetings are the random greetings that will be assigned to sessions.
    var greetings = []string{
    	"Hello World",
    	"Hallo Welt",
    	"Ciao Mondo",
    	"Salut le Monde",
    	"Hola Mundo",
    }
    
  2. Selanjutnya, aplikasi menentukan fungsi main, yang membuat instance app baru, mendaftarkan pengendali indeks, dan memulai server HTTP. Fungsi newApp membuat instance app dengan menyetel nilai projectID dan collectionID serta mengurai template HTML.

    func main() {
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    	}
    
    	projectID := os.Getenv("GOOGLE_CLOUD_PROJECT")
    	if projectID == "" {
    		log.Fatal("GOOGLE_CLOUD_PROJECT must be set")
    	}
    
    	// collectionID is a non-empty identifier for this app, it is used as the Firestore
    	// collection name that stores the sessions.
    	//
    	// Set it to something more descriptive for your app.
    	collectionID := "hello-views"
    
    	a, err := newApp(projectID, collectionID)
    	if err != nil {
    		log.Fatalf("newApp: %v", err)
    	}
    
    	http.HandleFunc("/", a.index)
    
    	log.Printf("Listening on port %s", port)
    	if err := http.ListenAndServe(":"+port, nil); err != nil {
    		log.Fatal(err)
    	}
    }
    
    // newApp creates a new app.
    func newApp(projectID, collectionID string) (app, error) {
    	tmpl, err := template.New("Index").Parse(`<body>{{.Views}} {{if eq .Views 1}}view{{else}}views{{end}} for "{{.Greetings}}"</body>`)
    	if err != nil {
    		log.Fatalf("template.New: %v", err)
    	}
    
    	return app{
    		tmpl:         tmpl,
    		collectionID: collectionID,
    		projectID:    projectID,
    	}, nil
    }
    
  3. Handler indeks mendapatkan sesi pengguna, dan membuat sesi jika diperlukan. Sesi baru diberi bahasa acak dan jumlah penayangan 0. Kemudian, jumlah penayangan bertambah satu, sesi disimpan, dan template HTML menulis respons.

    
    // index uses sessions to assign users a random greeting and keep track of
    // views.
    func (a *app) index(w http.ResponseWriter, r *http.Request) {
    	// Allows requests only for the root path ("/") to prevent duplicate calls.
    	if r.RequestURI != "/" {
    		http.NotFound(w, r)
    		return
    	}
    
    	var session session
    	var doc *firestore.DocumentRef
    
    	isNewSession := false
    
    	ctx := context.Background()
    
    	client, err := firestore.NewClient(ctx, a.projectID)
    	if err != nil {
    		log.Fatalf("firestore.NewClient: %v", err)
    	}
    	defer client.Close()
    
    	// cookieName is a non-empty identifier for this app, it is used as the key name
    	// that contains the session's id value.
    	//
    	// Set it to something more descriptive for your app.
    	cookieName := "session_id"
    
    	// If err is different to nil, it means the cookie has not been set, so it will be created.
    	cookie, err := r.Cookie(cookieName)
    	if err != nil {
    		// isNewSession flag is set to true
    		isNewSession = true
    	}
    
    	// If isNewSession flag is true, the session will be created
    	if isNewSession {
    		// Get unique id for new document
    		doc = client.Collection(a.collectionID).NewDoc()
    
    		session.Greetings = greetings[rand.Intn(len(greetings))]
    		session.Views = 1
    
    		// Cookie is set
    		cookie = &http.Cookie{
    			Name:  cookieName,
    			Value: doc.ID,
    		}
    		http.SetCookie(w, cookie)
    	} else {
    		// The session exists
    
    		// Retrieve document from collection by ID
    		docSnapshot, err := client.Collection(a.collectionID).Doc(cookie.Value).Get(ctx)
    		if err != nil {
    			log.Printf("doc.Get error: %v", err)
    			http.Error(w, "Error getting session", http.StatusInternalServerError)
    			return
    		}
    
    		// Unmarshal documents's content to local type
    		err = docSnapshot.DataTo(&session)
    		if err != nil {
    			log.Printf("doc.DataTo error: %v", err)
    			http.Error(w, "Error parsing session", http.StatusInternalServerError)
    			return
    		}
    
    		doc = docSnapshot.Ref
    
    		// Add 1 to current views value
    		session.Views++
    	}
    
    	// The document is created/updated
    	_, err = doc.Set(ctx, session)
    	if err != nil {
    		log.Printf("doc.Set error: %v", err)
    		http.Error(w, "Error creating session", http.StatusInternalServerError)
    		return
    	}
    
    	if err := a.tmpl.Execute(w, session); err != nil {
    		log.Printf("Execute: %v", err)
    	}
    }
    

    Diagram berikut mengilustrasikan cara Firestore menangani sesi untuk aplikasi Cloud Run.

    Diagram arsitektur: pengguna, Cloud Run, Firestore.

Menghapus sesi

Anda dapat menghapus data sesi di konsolGoogle Cloud atau menerapkan strategi penghapusan otomatis. Jika Anda menggunakan solusi penyimpanan untuk sesi seperti Memcache atau Redis, sesi yang sudah berakhir akan otomatis dihapus.

Berjalan secara lokal

  1. Di jendela terminal, buat biner sessions:

    go build
    
  2. Mulai server HTTP:

    ./sessions
    
  3. Lihat aplikasi di browser web Anda:

    Cloud Shell

    Di toolbar Cloud Shell, klik Web preview Pratinjau web dan pilih Preview on port 8080.

    Komputer lokal

    Di browser Anda, buka http://localhost:8080

    Anda akan melihat salah satu dari lima ucapan: “Hello World”, “Hallo Welt”, "Hola mundo”, “Salut le Monde”, atau “Ciao Mondo”. Bahasa akan berubah jika Anda membuka halaman di browser lain atau dalam mode samaran. Anda dapat melihat dan mengedit data sesi di konsolGoogle Cloud .

    Sesi Firestore di konsol Google Cloud .

  4. Untuk menghentikan server HTTP, di jendela terminal, tekan Control+C.

Men-deploy dan menjalankan di Cloud Run

Anda dapat menggunakan Cloud Run untuk membangun dan men-deploy aplikasi yang berjalan dengan andal meskipun menangani beban berat dan dengan jumlah data yang besar.

  1. Men-deploy aplikasi di Cloud Run:
        gcloud run deploy firestore-tutorial-go 
    --source . --allow-unauthenticated --port=8080
    --set-env-vars=GOOGLE_CLOUD_PROJECT=YOUR_PROJECT_ID
  2. Buka URL yang ditampilkan oleh perintah ini untuk melihat cara data sesi tetap ada di antara pemuatan halaman.

Ucapan kini dikirim oleh server web yang berjalan di instance Cloud Run.

Men-debug aplikasi

Jika Anda tidak dapat terhubung ke aplikasi Cloud Run, periksa hal berikut:

  1. Periksa apakah perintah deployment gcloud berhasil diselesaikan dan tidak menampilkan error apa pun. Jika ada error (misalnya, message=Build failed), perbaiki, lalu coba men-deploy aplikasi Cloud Run lagi.
  2. Di konsol Google Cloud , buka halaman Logs Explorer.

    Buka halaman Logs Explorer

    1. Di menu drop-down Recently selected resources, klik Cloud Run Application, lalu klik All module_id. Anda akan melihat daftar permintaan dari saat Anda mengunjungi aplikasi. Jika Anda tidak melihat daftar permintaan, pastikan Anda memilih Semua module_id dari daftar drop-down. Jika Anda melihat pesan error yang dicetak ke konsol Google Cloud , periksa apakah kode aplikasi Anda cocok dengan kode di bagian tentang penulisan aplikasi web.

    2. Pastikan Firestore API diaktifkan.

Pembersihan

Menghapus project

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Menghapus instance Cloud Run

  1. In the Google Cloud console, go to the Versions page for App Engine.

    Go to Versions

  2. Select the checkbox for the non-default app version that you want to delete.
  3. Untuk menghapus versi aplikasi, klik Hapus.

Langkah berikutnya