Cách sử dụng blobstore của App Engine (Mô-đun 15)

1. Tổng quan

Loạt lớp học lập trình Serverless Migration Station (hướng dẫn thực hành, tự học) và các video có liên quan nhằm giúp các nhà phát triển không máy chủ của Google Cloud hiện đại hoá ứng dụng của họ bằng cách hướng dẫn họ thực hiện một hoặc nhiều quá trình di chuyển, chủ yếu là chuyển khỏi các dịch vụ cũ. Việc này giúp ứng dụng của bạn dễ di chuyển hơn, đồng thời mang đến cho bạn nhiều lựa chọn và tính linh hoạt hơn, cho phép bạn tích hợp và truy cập vào nhiều sản phẩm Cloud hơn, cũng như dễ dàng nâng cấp lên các bản phát hành ngôn ngữ mới hơn. Mặc dù ban đầu tập trung vào những người dùng Cloud sớm nhất, chủ yếu là các nhà phát triển App Engine (môi trường tiêu chuẩn), nhưng loạt bài này đủ rộng để bao gồm các nền tảng không máy chủ khác như Cloud Functions và Cloud Run hoặc các nền tảng khác nếu có.

Lớp học lập trình Mô-đun 15 này giải thích cách thêm cách sử dụng blobstore của App Engine vào ứng dụng mẫu từ Mô-đun 0. Sau đó, bạn sẽ sẵn sàng di chuyển dữ liệu sử dụng đó sang Cloud Storage trong Học phần 16.

Bạn sẽ tìm hiểu cách

  • Thêm cách sử dụng API/thư viện App Engine Blobstore
  • Lưu trữ nội dung tải lên của người dùng vào dịch vụ blobstore
  • Chuẩn bị cho bước tiếp theo để di chuyển sang Cloud Storage

Bạn cần có

Bản khảo sát

Bạn sẽ sử dụng hướng dẫn này như thế nào?

Chỉ đọc hết Đọc và hoàn thành bài tập

Bạn đánh giá thế nào về trải nghiệm của mình với Python?

Mới làm quen Trung cấp Thành thạo

Bạn đánh giá thế nào về trải nghiệm sử dụng các dịch vụ của Google Cloud?

Mới bắt đầu Trung cấp Thành thạo

2. Thông tin cơ bản

Để di chuyển từ API Blobstore của App Engine, hãy thêm cách sử dụng API này vào ứng dụng ndb App Engine cơ sở hiện có trong Mô-đun 0. Ứng dụng mẫu hiển thị 10 lượt truy cập gần đây nhất cho người dùng. Chúng tôi đang sửa đổi ứng dụng để nhắc người dùng cuối tải một cấu phần phần mềm (tệp) lên tương ứng với "lượt truy cập" của họ. Nếu người dùng không muốn làm như vậy, họ có thể chọn "bỏ qua". Bất kể quyết định của người dùng là gì, trang tiếp theo sẽ hiển thị kết quả giống như ứng dụng trong Mô-đun 0 (và nhiều mô-đun khác trong loạt bài này). Sau khi triển khai tính năng tích hợp blobstore của App Engine, chúng ta có thể di chuyển tính năng này sang Cloud Storage trong lớp học lập trình tiếp theo (Mô-đun 16).

App Engine cung cấp quyền truy cập vào hệ thống tạo mẫu Django và Jinja2. Một điểm khác biệt của ví dụ này (ngoài việc thêm quyền truy cập vào Blobstore) là chuyển từ việc sử dụng Django trong Mô-đun 0 sang Jinja2 trong Mô-đun 15. Một bước quan trọng trong việc hiện đại hoá ứng dụng App Engine là di chuyển khung web từ webapp2 sang Flask. Python 3 sử dụng Jinja2 làm hệ thống tạo mẫu mặc định, vì vậy, chúng tôi bắt đầu chuyển sang hướng đó bằng cách triển khai Jinja2 trong khi vẫn sử dụng webapp2 để truy cập Blobstore. Vì Flask sử dụng Jinja2 theo mặc định, nên bạn không cần thay đổi mẫu trong Học phần 16.

3. Thiết lập/Chuẩn bị

Trước khi chuyển sang phần chính của hướng dẫn, hãy thiết lập dự án, lấy mã và triển khai ứng dụng cơ sở để bắt đầu với mã hoạt động.

1. Thiết lập dự án

Nếu đã triển khai ứng dụng của Mô-đun 0, bạn nên sử dụng lại cùng một dự án (và mã). Ngoài ra, bạn có thể tạo một dự án hoàn toàn mới hoặc sử dụng lại một dự án hiện có khác. Đảm bảo dự án có tài khoản thanh toán đang hoạt động và App Engine được bật.

2. Tải ứng dụng mẫu cơ sở

Một trong những điều kiện tiên quyết của lớp học lập trình này là bạn phải có một ứng dụng mẫu đang hoạt động của Mô-đun 0. Nếu chưa có, bạn có thể lấy ứng dụng này từ thư mục "START" (BẮT ĐẦU) của Mô-đun 0 (đường liên kết bên dưới). Lớp học lập trình này sẽ hướng dẫn bạn từng bước, kết thúc bằng mã tương tự như mã trong thư mục "FINISH" (HOÀN THÀNH) của Mô-đun 15.

Thư mục của các tệp START trong Học phần 0 sẽ có dạng như sau:

$ ls
README.md               index.html
app.yaml                main.py

3. Triển khai (lại) ứng dụng cơ sở

Các bước chuẩn bị còn lại mà bạn cần thực hiện ngay:

  1. Làm quen lại với công cụ dòng lệnh gcloud
  2. Triển khai lại ứng dụng mẫu bằng gcloud app deploy
  3. Xác nhận ứng dụng chạy trên App Engine mà không gặp vấn đề

Sau khi thực hiện thành công các bước đó và thấy ứng dụng web của mình hoạt động (với kết quả tương tự như bên dưới), bạn đã sẵn sàng thêm tính năng lưu vào bộ nhớ đệm vào ứng dụng của mình.

a7a9d2b80d706a2b.png

4. Cập nhật tệp cấu hình

app.yaml

Không có thay đổi quan trọng nào đối với cấu hình ứng dụng, tuy nhiên, như đã đề cập trước đó, chúng tôi sẽ chuyển từ mẫu Django (mặc định) sang Jinja2. Vì vậy, để chuyển đổi, người dùng nên chỉ định phiên bản mới nhất của Jinja2 hiện có trên máy chủ App Engine và bạn thực hiện việc này bằng cách thêm phiên bản đó vào phần thư viện tích hợp sẵn của bên thứ ba trong app.yaml.

TRƯỚC:

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

Chỉnh sửa tệp app.yaml bằng cách thêm một phần libraries mới như bạn thấy ở đây:

SAU:

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

libraries:
- name: jinja2
  version: latest

Không cần cập nhật tệp cấu hình nào khác, vì vậy, hãy chuyển sang tệp ứng dụng.

5. Sửa đổi tệp ứng dụng

Hỗ trợ nhập và Jinja2

Tập hợp thay đổi đầu tiên cho main.py bao gồm việc thêm cách sử dụng Blobstore API và thay thế mẫu Django bằng Jinja2. Sau đây là những thay đổi:

  1. Mục đích của mô-đun os là tạo tên đường dẫn tệp cho mẫu Django. Vì chúng ta đang chuyển sang Jinja2 (nơi xử lý việc này), nên không cần sử dụng os cũng như trình kết xuất mẫu Django google.appengine.ext.webapp.template nữa, vì vậy, chúng sẽ bị xoá.
  2. Nhập Blobstore API: google.appengine.ext.blobstore
  3. Nhập trình xử lý Blobstore có trong khung webapp ban đầu – các trình xử lý này không có trong webapp2: google.appengine.ext.webapp.blobstore_handlers
  4. Nhập tính năng hỗ trợ Jinja2 từ gói webapp2_extras

TRƯỚC:

import os
import webapp2
from google.appengine.ext import ndb
from google.appengine.ext.webapp import template

Triển khai các thay đổi trong danh sách trên bằng cách thay thế phần nhập hiện tại trong main.py bằng đoạn mã dưới đây.

SAU:

import webapp2
from webapp2_extras import jinja2
from google.appengine.ext import blobstore, ndb
from google.appengine.ext.webapp import blobstore_handlers

Sau khi nhập, hãy thêm một số mã nguyên mẫu để hỗ trợ việc sử dụng Jinja2 như được xác định trong tài liệu về webapp2_extras. Đoạn mã sau đây gói lớp trình xử lý yêu cầu webapp2 tiêu chuẩn bằng chức năng Jinja2, vì vậy, hãy thêm khối mã này vào main.py ngay sau lệnh nhập:

class BaseHandler(webapp2.RequestHandler):
    'Derived request handler mixing-in Jinja2 support'
    @webapp2.cached_property
    def jinja2(self):
        return jinja2.get_jinja2(app=self.app)

    def render_response(self, _template, **context):
        self.response.write(self.jinja2.render_template(_template, **context))

Thêm tính năng hỗ trợ Blobstore

Không giống như các hoạt động di chuyển khác trong loạt bài này, nơi chúng tôi giữ nguyên chức năng hoặc kết quả của ứng dụng mẫu (hoặc gần như giống nhau) mà không thay đổi (nhiều) đối với trải nghiệm người dùng, ví dụ này có sự khác biệt rõ rệt so với thông thường. Thay vì đăng ký ngay một lượt truy cập mới rồi hiển thị 10 lượt truy cập gần đây nhất, chúng ta sẽ cập nhật ứng dụng để yêu cầu người dùng cung cấp một cấu phần phần mềm tệp để đăng ký lượt truy cập của họ. Sau đó, người dùng cuối có thể tải tệp tương ứng lên hoặc chọn "Bỏ qua" để không tải tệp nào lên. Sau khi hoàn tất bước này, trang "lượt truy cập gần đây nhất" sẽ xuất hiện.

Thay đổi này cho phép ứng dụng của chúng ta sử dụng dịch vụ Blobstore để lưu trữ (và có thể hiển thị sau này) hình ảnh đó hoặc loại tệp khác trên trang lượt truy cập gần đây nhất.

Cập nhật mô hình dữ liệu và triển khai việc sử dụng mô hình đó

Chúng tôi đang lưu trữ thêm dữ liệu, cụ thể là cập nhật mô hình dữ liệu để lưu trữ mã nhận dạng (gọi là "BlobKey") của tệp được tải lên Blobstore và thêm một tệp đối chiếu để lưu tệp đó trong store_visit(). Vì dữ liệu bổ sung này được trả về cùng với mọi dữ liệu khác khi truy vấn, nên fetch_visits() vẫn giữ nguyên.

Sau đây là hình ảnh trước và sau khi áp dụng những điểm cập nhật này, trong đó có file_blob, một ndb.BlobKeyProperty:

TRƯỚC:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    return Visit.query().order(-Visit.timestamp).fetch(limit)

SAU:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)
    file_blob = ndb.BlobKeyProperty()

def store_visit(remote_addr, user_agent, upload_key):
    'create new Visit entity in Datastore'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent),
            file_blob=upload_key).put()

def fetch_visits(limit):
    'get most recent visits'
    return Visit.query().order(-Visit.timestamp).fetch(limit)

Sau đây là hình ảnh minh hoạ những thay đổi đã được thực hiện cho đến nay:

2270783776759f7f.png

Hỗ trợ tải tệp lên

Thay đổi quan trọng nhất về chức năng là hỗ trợ tải tệp lên, cho dù là nhắc người dùng tải tệp lên, hỗ trợ tính năng "bỏ qua" hay hiển thị tệp tương ứng với một lượt truy cập. Tất cả đều là một phần của bức tranh. Sau đây là những thay đổi cần thiết để hỗ trợ việc tải tệp lên:

  1. Yêu cầu của trình xử lý chính GET không còn tìm nạp các lượt truy cập gần đây nhất để hiển thị. Thay vào đó, ứng dụng sẽ nhắc người dùng tải lên.
  2. Khi người dùng cuối gửi tệp để tải lên hoặc bỏ qua quy trình đó, POST từ biểu mẫu sẽ chuyển quyền kiểm soát sang UploadHandler mới, bắt nguồn từ google.appengine.ext.webapp.blobstore_handlers.BlobstoreUploadHandler.
  3. Phương thức POST của UploadHandler thực hiện việc tải lên, gọi store_visit() để đăng ký lượt truy cập và kích hoạt lệnh chuyển hướng HTTP 307 để đưa người dùng trở lại "/", nơi...
  4. Phương thức POST của trình xử lý chính truy vấn (thông qua fetch_visits()) và hiển thị các lượt truy cập gần đây nhất. Nếu người dùng chọn "bỏ qua", thì không có tệp nào được tải lên, nhưng lượt truy cập vẫn được đăng ký, sau đó là cùng một lệnh chuyển hướng.
  5. Màn hình hiển thị các lượt truy cập gần đây nhất có một trường mới hiển thị cho người dùng, đó là "xem" có siêu liên kết nếu có tệp tải lên hoặc "không có" nếu không có tệp tải lên. Những thay đổi này được thực hiện trong mẫu HTML cùng với việc bổ sung biểu mẫu tải lên (sẽ sớm có thêm thông tin về biểu mẫu này).
  6. Nếu người dùng cuối nhấp vào đường liên kết "xem" cho bất kỳ lượt truy cập nào có video đã tải lên, thì thao tác này sẽ gửi một yêu cầu GET đến một ViewBlobHandler mới, bắt nguồn từ google.appengine.ext.webapp.blobstore_handlers.BlobstoreDownloadHandler, hiển thị tệp nếu là hình ảnh (trong trình duyệt nếu được hỗ trợ), nhắc tải xuống nếu không phải hình ảnh hoặc trả về lỗi HTTP 404 nếu không tìm thấy.
  7. Ngoài cặp lớp trình xử lý mới cũng như cặp tuyến mới để gửi lưu lượng truy cập đến các lớp đó, trình xử lý chính cần có một phương thức POST mới để nhận lệnh chuyển hướng 307 được mô tả ở trên.

Trước khi cập nhật, ứng dụng Mô-đun 0 chỉ có một trình xử lý chính với phương thức GET và một tuyến duy nhất:

TRƯỚC:

class MainHandler(webapp2.RequestHandler):
    'main application (GET) handler'
    def get(self):
        store_visit(self.request.remote_addr, self.request.user_agent)
        visits = fetch_visits(10)
        tmpl = os.path.join(os.path.dirname(__file__), 'index.html')
        self.response.out.write(template.render(tmpl, {'visits': visits}))

app = webapp2.WSGIApplication([
    ('/', MainHandler),
], debug=True)

Sau khi triển khai các bản cập nhật đó, giờ đây sẽ có 3 trình xử lý: 1) trình xử lý tải lên bằng phương thức POST, 2) trình xử lý tải xuống "view blob" bằng phương thức GET và 3) trình xử lý chính bằng phương thức GET và POST. Thực hiện những thay đổi này để phần còn lại của ứng dụng trông giống như bên dưới.

SAU:

class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    'Upload blob (POST) handler'
    def post(self):
        uploads = self.get_uploads()
        blob_id = uploads[0].key() if uploads else None
        store_visit(self.request.remote_addr, self.request.user_agent, blob_id)
        self.redirect('/', code=307)

class ViewBlobHandler(blobstore_handlers.BlobstoreDownloadHandler):
    'view uploaded blob (GET) handler'
    def get(self, blob_key):
        self.send_blob(blob_key) if blobstore.get(blob_key) else self.error(404)

class MainHandler(BaseHandler):
    'main application (GET/POST) handler'
    def get(self):
        self.render_response('index.html',
                upload_url=blobstore.create_upload_url('/upload'))

    def post(self):
        visits = fetch_visits(10)
        self.render_response('index.html', visits=visits)

app = webapp2.WSGIApplication([
    ('/', MainHandler),
    ('/upload', UploadHandler),
    ('/view/([^/]+)?', ViewBlobHandler),
], debug=True)

Có một số lệnh gọi chính trong đoạn mã mà chúng ta vừa thêm:

  • Trong MainHandler.get, có một lệnh gọi đến blobstore.create_upload_url. Lệnh gọi này tạo URL mà biểu mẫu POST đến, gọi trình xử lý tải lên để gửi tệp đến Blobstore.
  • Trong UploadHandler.post, có một lệnh gọi đến blobstore_handlers.BlobstoreUploadHandler.get_uploads. Đây là điều kỳ diệu thực sự giúp đưa tệp vào Blobstore và trả về một mã nhận dạng duy nhất và cố định cho tệp đó, tức là BlobKey.
  • Trong ViewBlobHandler.get, việc gọi blobstore_handlers.BlobstoreDownloadHandler.send bằng BlobKey của tệp sẽ dẫn đến việc tìm nạp tệp và chuyển tiếp tệp đó đến trình duyệt của người dùng cuối

Những lệnh gọi này đại diện cho phần lớn quyền truy cập vào các tính năng được thêm vào ứng dụng. Sau đây là hình ảnh minh hoạ cho nhóm thay đổi thứ hai và cũng là nhóm thay đổi cuối cùng đối với main.py:

da2960525ac1b90d.png

Cập nhật mẫu HTML

Một số nội dung cập nhật cho ứng dụng chính ảnh hưởng đến giao diện người dùng (UI) của ứng dụng, vì vậy, bạn cần thực hiện các thay đổi tương ứng trong mẫu web, cụ thể là hai thay đổi:

  1. Bạn cần có một biểu mẫu tải tệp lên với 3 phần tử nhập: một tệp và một cặp nút gửi để tải tệp lên và bỏ qua.
  2. Cập nhật kết quả của các lượt truy cập gần đây nhất bằng cách thêm đường liên kết "xem" cho các lượt truy cập có tệp tải lên tương ứng hoặc "không có" nếu không có tệp tải lên.

TRƯỚC:

<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
<body>

<h1>VisitMe example</h1>
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
    <li>{{ visit.timestamp.ctime }} from {{ visit.visitor }}</li>
{% endfor %}
</ul>

</body>
</html>

Triển khai các thay đổi trong danh sách ở trên để tạo mẫu mới:

SAU:

<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
<body>

<h1>VisitMe example</h1>
{% if upload_url %}

<h3>Welcome... upload a file? (optional)</h3>
<form action="{{ upload_url }}" method="POST" enctype="multipart/form-data">
    <input type="file" name="file"><p></p>
    <input type="submit"> <input type="submit" value="Skip">
</form>

{% else %}

<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
<li>{{ visit.timestamp.ctime() }}
    <i><code>
    {% if visit.file_blob %}
        (<a href="/view/{{ visit.file_blob }}" target="_blank">view</a>)
    {% else %}
        (none)
    {% endif %}
    </code></i>
    from {{ visit.visitor }}
</li>
{% endfor %}
</ul>

{% endif %}

</body>
</html>

Hình ảnh này minh hoạ những nội dung cập nhật bắt buộc đối với index.html:

8583e975f25aa9e7.png

Thay đổi cuối cùng là Jinja2 ưu tiên các mẫu trong thư mục templates, vì vậy, hãy tạo thư mục đó và di chuyển index.html vào trong thư mục đó. Với bước cuối cùng này, bạn đã hoàn tất mọi thay đổi cần thiết để thêm việc sử dụng Blobstore vào ứng dụng mẫu của Mô-đun 0.

(không bắt buộc) "Cải tiến" Cloud Storage

Bộ nhớ Blobstore cuối cùng đã phát triển thành Cloud Storage. Điều này có nghĩa là các tệp tải lên Blobstore sẽ xuất hiện trong Cloud Console, cụ thể là trình duyệt Cloud Storage. Câu hỏi là ở đâu. Câu trả lời là bộ chứa Cloud Storage mặc định của ứng dụng App Engine. Tên của bộ chứa này là tên miền đầy đủ của ứng dụng App Engine, PROJECT_ID.appspot.com. Điều này rất thuận tiện vì tất cả mã dự án đều là duy nhất, đúng không?

Nội dung cập nhật cho ứng dụng mẫu sẽ thả các tệp đã tải lên vào bộ chứa đó, nhưng nhà phát triển có thể chọn một vị trí cụ thể hơn. Bạn có thể truy cập vào bộ chứa mặc định theo phương thức lập trình thông qua google.appengine.api.app_identity.get_default_gcs_bucket_name(). Bạn cần nhập một giá trị mới nếu muốn truy cập vào giá trị này, chẳng hạn như để sử dụng làm tiền tố cho việc sắp xếp các tệp đã tải lên. Ví dụ: sắp xếp theo loại tệp:

f61f7a23a1518705.png

Ví dụ: để triển khai một tính năng tương tự cho hình ảnh, bạn sẽ có mã như sau cùng với một số mã kiểm tra loại tệp để chọn tên bộ chứa mong muốn:

ROOT_BUCKET = app_identity.get_default_gcs_bucket_name()
IMAGE_BUCKET = '%s/%s' % (ROOT_BUCKET, 'images')

Bạn cũng sẽ xác thực hình ảnh đã tải lên bằng một công cụ như mô-đun imghdr của Thư viện chuẩn Python để xác nhận loại hình ảnh. Cuối cùng, bạn có thể muốn giới hạn kích thước của tệp tải lên để đề phòng các đối tượng xấu.

Giả sử bạn đã thực hiện tất cả những việc đó. Làm cách nào để cập nhật ứng dụng nhằm hỗ trợ việc chỉ định nơi lưu trữ tệp đã tải lên? Mấu chốt là điều chỉnh lệnh gọi đến blobstore.create_upload_url trong MainHandler.get để chỉ định vị trí mong muốn trong Cloud Storage cho tệp tải lên bằng cách thêm tham số gs_bucket_name như sau:

blobstore.create_upload_url('/upload', gs_bucket_name=IMAGE_BUCKET))

Vì đây là bản cập nhật không bắt buộc nếu bạn muốn chỉ định nơi tải lên, nên bản cập nhật này không nằm trong tệp main.py trong kho lưu trữ. Thay vào đó, bạn có thể xem xét một giải pháp thay thế có tên là main-gcs.py trong kho lưu trữ. Thay vì sử dụng một "thư mục" bộ chứa riêng biệt, mã trong main-gcs.py sẽ lưu trữ các tệp tải lên trong bộ chứa "gốc" (PROJECT_ID.appspot.com) giống như main.py nhưng cung cấp cấu trúc cần thiết nếu bạn muốn phát triển mẫu thành một thứ gì đó khác như được gợi ý trong phần này. Dưới đây là hình minh hoạ về "sự khác biệt" giữa main.py và main-gcs.py.

256e1ea68241a501.png

6. Tóm tắt/Dọn dẹp

Phần này kết thúc lớp học lập trình này bằng cách triển khai ứng dụng, xác minh ứng dụng hoạt động như dự kiến và trong mọi kết quả được phản ánh. Sau khi xác thực ứng dụng, hãy thực hiện mọi bước dọn dẹp và cân nhắc các bước tiếp theo.

Triển khai và xác minh ứng dụng

Triển khai lại ứng dụng bằng gcloud app deploy và xác nhận ứng dụng hoạt động như quảng cáo, khác với trải nghiệm người dùng (UX) của ứng dụng Mô-đun 0. Hiện có hai màn hình khác nhau trong ứng dụng của bạn, màn hình đầu tiên là lời nhắc biểu mẫu tải tệp lên:

f5b5f9f19d8ae978.pngTại đây, người dùng cuối có thể tải tệp lên rồi nhấp vào "Gửi" hoặc nhấp vào "Bỏ qua" để không tải tệp nào lên. Trong cả hai trường hợp, kết quả là màn hình lượt truy cập gần đây nhất, hiện được bổ sung các đường liên kết "xem" hoặc "không có" giữa dấu thời gian của lượt truy cập và thông tin khách truy cập:

f5ac6b98ee8a34cb.png

Chúc mừng bạn đã hoàn thành lớp học lập trình này về việc thêm Blobstore của App Engine vào ứng dụng mẫu của Mô-đun 0. Mã của bạn hiện đã khớp với mã trong thư mục FINISH (Mô-đun 15). main-gcs.py thay thế cũng có trong thư mục đó.

Dọn dẹp

Giải pháp chung

Nếu đã hoàn tất, bạn nên tắt ứng dụng App Engine để tránh phát sinh phí. Tuy nhiên, nếu bạn muốn thử nghiệm thêm, nền tảng App Engine có hạn mức miễn phí và miễn là bạn không vượt quá hạn mức sử dụng đó, bạn sẽ không bị tính phí. Đó là chi phí cho tài nguyên điện toán, nhưng cũng có thể có phí cho các dịch vụ App Engine có liên quan, vì vậy, hãy xem trang giá của App Engine để biết thêm thông tin. Nếu quá trình di chuyển này liên quan đến các dịch vụ khác của Cloud, thì các dịch vụ đó sẽ được tính phí riêng. Trong cả hai trường hợp, nếu có, hãy xem phần "Cụ thể cho lớp học lập trình này" bên dưới.

Để minh bạch hoàn toàn, việc triển khai lên một nền tảng điện toán không máy chủ của Google Cloud như App Engine sẽ phát sinh chi phí xây dựng và lưu trữ nhỏ. Cloud Build có hạn mức miễn phí riêng, tương tự như Cloud Storage. Việc lưu trữ hình ảnh đó sẽ sử dụng một phần hạn mức. Tuy nhiên, bạn có thể sống ở một khu vực không có hạn mức miễn phí như vậy, vì vậy, hãy lưu ý đến mức sử dụng bộ nhớ của bạn để giảm thiểu chi phí tiềm ẩn. Các "thư mục" cụ thể trên Cloud Storage mà bạn nên xem xét bao gồm:

  • console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
  • console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
  • Các đường liên kết đến bộ nhớ ở trên phụ thuộc vào PROJECT_ID và *LOC*ation của bạn, ví dụ: "us" nếu ứng dụng của bạn được lưu trữ ở Hoa Kỳ.

Mặt khác, nếu bạn không tiếp tục với ứng dụng này hoặc các lớp học lập trình di chuyển có liên quan khác và muốn xoá hoàn toàn mọi thứ, hãy tắt dự án của bạn.

Dành riêng cho lớp học lập trình này

Các dịch vụ được liệt kê dưới đây chỉ dành riêng cho lớp học lập trình này. Hãy tham khảo tài liệu của từng sản phẩm để biết thêm thông tin:

Các bước tiếp theo

Quá trình di chuyển hợp lý tiếp theo cần xem xét được đề cập trong Mô-đun 16, hướng dẫn nhà phát triển cách di chuyển từ dịch vụ Blobstore của App Engine sang sử dụng thư viện ứng dụng Cloud Storage. Lợi ích của việc nâng cấp bao gồm việc có thể sử dụng nhiều tính năng hơn của Cloud Storage, làm quen với thư viện ứng dụng hoạt động cho các ứng dụng bên ngoài App Engine, cho dù là trong Google Cloud, các đám mây khác hay thậm chí là tại chỗ. Nếu cảm thấy không cần tất cả các tính năng của Cloud Storage hoặc lo ngại về ảnh hưởng của dịch vụ này đối với chi phí, bạn có thể tiếp tục sử dụng App Engine Blobstore.

Ngoài Mô-đun 16, còn có một loạt các hoạt động di chuyển khác có thể thực hiện, chẳng hạn như Cloud NDB và Cloud Datastore, Cloud Tasks hoặc Cloud Memorystore. Ngoài ra, còn có các hoạt động di chuyển giữa các sản phẩm sang Cloud Run và Cloud Functions. Kho lưu trữ di chuyển có tất cả mã mẫu, liên kết bạn đến tất cả lớp học lập trình và video hiện có, đồng thời cung cấp hướng dẫn về những hoạt động di chuyển cần xem xét và mọi "thứ tự" di chuyển có liên quan.

7. Tài nguyên khác

Vấn đề/ý kiến phản hồi về lớp học lập trình

Nếu bạn phát hiện thấy vấn đề nào trong lớp học lập trình này, vui lòng tìm kiếm vấn đề đó trước khi gửi báo cáo. Đường liên kết để tìm kiếm và tạo vấn đề mới:

Tài nguyên di chuyển

Bạn có thể tìm thấy đường liên kết đến các thư mục kho lưu trữ cho Mô-đun 0 (BẮT ĐẦU) và Mô-đun 15 (KẾT THÚC) trong bảng dưới đây. Bạn cũng có thể truy cập vào các tệp này từ kho lưu trữ cho tất cả các hoạt động di chuyển trong lớp học lập trình App Engine. Bạn có thể sao chép hoặc tải tệp ZIP xuống.

Lớp học lập trình

Python 2

Python 3

Mô-đun 0

mã

Không có

Mô-đun 15 (lớp học lập trình này)

mã

Không có

Tài nguyên trực tuyến

Dưới đây là các tài nguyên trực tuyến có thể liên quan đến hướng dẫn này:

App Engine

Google Cloud

Python

Video

Giấy phép

Tác phẩm này được cấp phép theo Giấy phép Ghi công theo Creative Commons 2.0 Chung.