Ringkasan Blobstore API untuk layanan paket lama

Blobstore API memungkinkan aplikasi Anda menyajikan objek data, yang disebut blob, dengan ukuran yang jauh lebih besar dari ukuran yang diizinkan untuk objek dalam layanan Datastore. Blob berguna untuk menyajikan file besar, seperti file video atau gambar, dan untuk memungkinkan pengguna mengupload file data berukuran besar. Blob dibuat dengan mengupload file melalui permintaan HTTP. Biasanya, aplikasi Anda akan melakukannya dengan menampilkan formulir yang berisi kolom upload file kepada pengguna. Saat formulir dikirimkan, Blobstore akan membuat blob dari konten file dan menampilkan referensi tersembunyi ke blob, yang disebut kunci blob yang nantinya dapat digunakan untuk menyajikan blob. Aplikasi dapat menyajikan nilai blob lengkap sebagai respons terhadap permintaan pengguna, atau dapat membaca nilai secara langsung menggunakan antarmuka seperti file streaming.

Memperkenalkan Blobstore

Google App Engine mencakup layanan Blobstore, yang memungkinkan aplikasi menyajikan objek data yang hanya dibatasi oleh jumlah data yang dapat diupload atau didownload melalui satu koneksi HTTP. Objek ini disebut nilai Blobstore atau blob. Nilai Blobstore berfungsi sebagai respons dari pengendali permintaan dan dibuat sebagai file yang diupload melalui formulir web. Aplikasi tidak membuat data blob secara langsung; sebagai gantinya, blob dibuat secara tidak langsung oleh formulir web yang dikirimkan atau permintaan POST HTTP lainnya. Nilai Blobstore dapat disajikan kepada pengguna, atau diakses oleh aplikasi dalam aliran data seperti file, menggunakan Blobstore API.

Untuk meminta pengguna mengupload nilai Blobstore, aplikasi Anda harus menyajikan formulir web dengan kolom upload file. Aplikasi ini membuat URL tindakan formulir dengan memanggil Blobstore API. Browser pengguna mengupload file langsung ke Blobstore melalui URL yang dibuat. Blobstore kemudian menyimpan blob, menulis ulang permintaan untuk memuat kunci blob, dan meneruskannya ke jalur dalam aplikasi Anda. Pengendali permintaan di jalur tersebut dalam aplikasi Anda bisa melakukan pemrosesan formulir tambahan.

Untuk menyajikan blob, aplikasi Anda menetapkan header pada respons keluar, dan App Engine mengganti respons tersebut dengan nilai blob.

Blob tidak dapat diubah setelah dibuat, meskipun dapat dihapus. Setiap blob memiliki catatan info blob yang sesuai dan tersimpan di datastore, yang memberikan detail tentang blob, seperti waktu pembuatan dan jenis kontennya. Anda dapat menggunakan kunci blob untuk mengambil catatan info blob dan melakukan kueri terhadap propertinya.

Menggunakan Blobstore

Aplikasi dapat menggunakan Blobstore untuk menerima file besar sebagai upload dari pengguna dan menyajikan file tersebut. File disebut blob setelah diupload. Aplikasi tidak mengakses blob secara langsung berdasarkan nama file. Sebagai gantinya, aplikasi merujuk ke blob melalui jenis appengine.BlobKey.

Pengguna membuat blob dengan mengirimkan formulir HTML yang menyertakan satu atau beberapa kolom input file. Aplikasi Anda menetapkan blobstore.UploadURL sebagai tujuan (tindakan) formulir ini, dengan meneruskan fungsi jalur URL pengendali di aplikasi Anda. Saat pengguna mengirimkan formulir, browser pengguna akan mengupload file yang ditentukan langsung ke Blobstore. Blobstore menulis ulang permintaan pengguna dan menyimpan data file yang diupload, mengganti data file yang diupload dengan satu atau beberapa kunci blob yang sesuai, lalu meneruskan permintaan yang ditulis ulang ke pengendali di jalur URL yang Anda berikan ke blobstore.UploadURL. Pengendali ini dapat melakukan pemrosesan tambahan berdasarkan kunci blob. Terakhir, pengendali harus menampilkan header saja, respons pengalihan (301, 302, atau 303), biasanya browser mengalihkan ke halaman lain yang menunjukkan status upload blob.

Aplikasi dapat membaca bagian dari nilai Blobstore menggunakan blobstore.Reader.

Mengupload blob

Untuk membuat dan mengupload blob, ikuti prosedur berikut:

1. Membuat URL upload

Panggil blobstore.UploadURL guna membuat URL upload untuk formulir yang akan diisi pengguna, yang meneruskan jalur aplikasi yang akan dimuat saat POST formulir selesai.

ctx := appengine.NewContext(r)
uploadURL, err := blobstore.UploadURL(ctx, "/upload", nil)
if err != nil {
	serveError(ctx, w, err)
	return
}

2. Membuat formulir upload

Formulir harus menyertakan kolom upload file, dan enctype formulir harus ditetapkan ke multipart/form-data. Saat pengguna mengirimkan formulir, POST akan ditangani oleh Blobstore API, yang membuat blob. API ini juga membuat catatan info untuk blob dan menyimpan catatan di datastore, dan meneruskan permintaan yang ditulis ulang ke aplikasi Anda di jalur yang diberikan sebagai kunci blob.

	var rootTemplate = template.Must(template.New("root").Parse(rootTemplateHTML))

	const rootTemplateHTML = `
<html><body>
<form action="{{.}}" method="POST" enctype="multipart/form-data">
Upload File: <input type="file" name="file"><br>
<input type="submit" name="submit" value="Submit">
</form></body></html>
`

3. Menerapkan pengendali upload

Dalam pengendali ini, Anda dapat menyimpan kunci blob bersama model data aplikasi lainnya. Kunci blob itu sendiri tetap dapat diakses dari entity info blob di datastore. Perhatikan bahwa setelah pengguna mengirimkan formulir dan pengendali Anda dipanggil, blob telah disimpan dan info blob ditambahkan ke datastore. Jika aplikasi Anda tidak ingin menyimpan blob, Anda harus segera menghapus blob agar tidak menjadi telantar:

ctx := appengine.NewContext(r)
blobs, _, err := blobstore.ParseUpload(r)
if err != nil {
	serveError(ctx, w, err)
	return
}
file := blobs["file"]
if len(file) == 0 {
	log.Errorf(ctx, "no file uploaded")
	http.Redirect(w, r, "/", http.StatusFound)
	return
}
http.Redirect(w, r, "/serve/?blobKey="+string(file[0].BlobKey), http.StatusFound)

Saat Blobstore menulis ulang permintaan pengguna, bagian MIME dari file yang diupload akan dikosongkan, dan kunci blob ditambahkan sebagai header bagian MIME. Semua kolom dan bagian formulir lainnya akan dipertahankan dan diteruskan ke pengendali upload. Jika Anda tidak menentukan jenis konten, Blobstore akan mencoba menyimpulkannya dari ekstensi file. Jika tidak ada jenis konten yang dapat ditentukan, blob yang baru dibuat akan ditetapkan sebagai jenis konten application/octet-stream.

Menampilkan blob

Untuk menyajikan blob, Anda harus menyertakan pengendali download blob sebagai jalur dalam aplikasi Anda. Pengendali ini harus meneruskan kunci blob untuk blob yang diinginkan ke blobstore.Send. Dalam contoh ini, kunci blob diteruskan ke pengendali download sebagai argumen URL r.FormValue("blobKey"). Dalam praktiknya, pengendali download bisa mendapatkan kunci blob dengan cara apa pun yang Anda pilih, misalnya melalui metode lain atau tindakan pengguna.

blobstore.Send(w, appengine.BlobKey(r.FormValue("blobKey")))

Blob dapat disajikan dari URL aplikasi apa pun. Untuk menyajikan blob dalam aplikasi Anda, tempatkan header khusus dalam respons yang berisi kunci blob. App Engine mengganti isi respons dengan konten blob.

Rentang byte blob

Blobstore mendukung penyajian sebagian dari nilai yang besar, bukan nilai penuh, sebagai respons atas permintaan. Untuk menyajikan nilai parsial, sertakan header X-AppEngine-BlobRange dalam respons keluar. Nilainya adalah rentang byte HTTP standar. Penomoran byte berbasis nol. X-AppEngine-BlobRange kosong menginstruksikan API untuk mengabaikan header rentang dan menyajikan blob lengkap. Contoh rentang mencakup:

  • 0-499 menyajikan 500 byte pertama dari nilai (0 hingga 499 byte, inklusif).
  • 500-999 menyajikan 500 byte dimulai dari byte 501.
  • 500- menyajikan semua byte yang dimulai dari byte 501 hingga akhir nilai.
  • -500 menyajikan 500 byte terakhir dari nilai.

Jika rentang byte valid untuk nilai Blobstore, Blobstore akan mengirimkan kode status 206 Partial Content dan rentang byte yang diminta ke klien. Jika rentang tidak valid untuk nilai tersebut, Blobstore akan mengirim 416 Requested Range Not Satisfiable.

Blobstore tidak mendukung beberapa rentang byte dalam satu permintaan (misalnya 100-199,200-299), terlepas dari apakah keduanya tumpang-tindih atau tidak.

Menyelesaikan aplikasi contoh

Pada aplikasi contoh berikut, URL utama aplikasi memuat formulir yang meminta pengguna untuk mengupload file, dan pengendali upload segera memanggil pengendali download untuk menyajikan data. Hal ini untuk menyederhanakan aplikasi contoh. Dalam praktiknya, Anda mungkin tidak akan menggunakan URL utama untuk meminta upload data, dan Anda juga tidak akan langsung menyajikan blob yang baru saja diupload.


package blobstore_example

import (
	"context"
	"html/template"
	"io"
	"net/http"

	"google.golang.org/appengine"
	"google.golang.org/appengine/blobstore"
	"google.golang.org/appengine/log"
)

func serveError(ctx context.Context, w http.ResponseWriter, err error) {
	w.WriteHeader(http.StatusInternalServerError)
	w.Header().Set("Content-Type", "text/plain")
	io.WriteString(w, "Internal Server Error")
	log.Errorf(ctx, "%v", err)
}

var rootTemplate = template.Must(template.New("root").Parse(rootTemplateHTML))

const rootTemplateHTML = `
<html><body>
<form action="{{.}}" method="POST" enctype="multipart/form-data">
Upload File: <input type="file" name="file"><br>
<input type="submit" name="submit" value="Submit">
</form></body></html>
`

func handleRoot(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)
	uploadURL, err := blobstore.UploadURL(ctx, "/upload", nil)
	if err != nil {
		serveError(ctx, w, err)
		return
	}
	w.Header().Set("Content-Type", "text/html")
	err = rootTemplate.Execute(w, uploadURL)
	if err != nil {
		log.Errorf(ctx, "%v", err)
	}
}

func handleServe(w http.ResponseWriter, r *http.Request) {
	blobstore.Send(w, appengine.BlobKey(r.FormValue("blobKey")))
}

func handleUpload(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)
	blobs, _, err := blobstore.ParseUpload(r)
	if err != nil {
		serveError(ctx, w, err)
		return
	}
	file := blobs["file"]
	if len(file) == 0 {
		log.Errorf(ctx, "no file uploaded")
		http.Redirect(w, r, "/", http.StatusFound)
		return
	}
	http.Redirect(w, r, "/serve/?blobKey="+string(file[0].BlobKey), http.StatusFound)
}

func init() {
	http.HandleFunc("/", handleRoot)
	http.HandleFunc("/serve/", handleServe)
	http.HandleFunc("/upload", handleUpload)
}

Menggunakan API Blobstore dengan Google Cloud Storage

Anda dapat menggunakan API Blobstore untuk menyimpan blob di Cloud Storage, bukan menyimpannya di Blobstore. Anda harus menyiapkan bucket seperti yang dijelaskan dalam dokumentasi Google Cloud Storage dan menentukan bucket serta nama file dalam UploadURLOptions yang Anda berikan ke fungsi UploadURL. Di pengendali upload, Anda perlu memproses peta yang ditampilkan dari blob yang ditampilkan dan secara eksplisit menyimpan nama file Google Cloud Storage yang diperlukan untuk mengambil blob di lain waktu.

Anda juga dapat menyajikan objek Cloud Storage menggunakan API Blobstore. Untuk menyajikan objek Cloud Storage, gunakan BlobKeyForFile untuk membuat blobkey yang diperlukan seperti yang dijelaskan dalam Menyajikan blob.

Kuota dan batas

Ruang yang digunakan untuk nilai Blobstore berkontribusi pada kuota Data Tersimpan (dapat ditagih). Entity info Blob di datastore diperhitungkan dalam batas terkait datastore. Perhatikan bahwa Google Cloud Storage adalah layanan bayar sesuai penggunaan; Anda akan dikenakan biaya sesuai dengan lembar harga Cloud Storage.

Untuk mengetahui informasi selengkapnya tentang kuota keamanan di seluruh sistem, lihat Kuota.

Selain kuota keamanan di seluruh sistem, batas berikut berlaku khusus untuk penggunaan Blobstore:

  • Ukuran maksimum data Blobstore yang dapat dibaca oleh aplikasi dengan satu panggilan API adalah 32 megabyte.
  • Jumlah file maksimum yang dapat diupload dalam satu format POST adalah 500.
Untuk informasi tentang cara mengatasi batas ukuran ini, lihat dokumentasi untuk fungsi Send.