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 theo tốc độ của riêng bạn) và các video liên quan nhằm giúp các nhà phát triển Google Cloud không máy chủ hiện đại hoá các ứ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 quy trình di chuyển, chủ yếu là chuyển từ các dịch vụ cũ. Làm như vậy sẽ giúp ứng dụng của bạn dễ dàng di chuyển hơn, đồng thời mang đến cho bạn nhiều lựa chọn và sự 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 trên đám mây 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 FunctionsCloud Run, hoặc ở những nơi khác nếu có thể.

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

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

  • Thêm việc sử dụng API/thư viện Blobstore của App Engine
  • Lưu trữ nội dung do người dùng tải lên 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 Đọ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?

Người mới bắt đầu Trung cấp Thành thạo

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

Người mới bắt đầu Trung cấp Thành thạo

2. Thông tin khái quát

Để di chuyển từ App Engine Blobstore API, hãy thêm việc sử dụng API này vào ứng dụng ndb App Engine cơ bản 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 của 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) tương ứng với "lượt truy cập" của họ. Nếu không muốn, người dùng 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ị cùng một đầu ra 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 chế độ tích hợp blobstore App Engine này, chúng ta có thể di chuyển chế độ tích hợp 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 các hệ thống tạo mẫu DjangoJinja2. 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à ví dụ này 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á các ứng dụng App Engine là di chuyển các khung web từ webapp2 sang Flask. Sau này, Jinja2 được dùng làm hệ thống tạo mẫu mặc định. Vì vậy, chúng ta sẽ bắt đầu chuyển sang hướng đó bằng cách triển khai Jinja2 trong khi vẫn dùng webapp2 để truy cập vào Blobstore. Vì Flask sử dụng Jinja2 theo mặc định, nên bạn không cần thay đổi mẫu trong Mô-đun 16.

3. Thiết lập/Công việc chuẩn bị

Trước khi bắt đầu 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 bằng mã hoạt động.

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

Nếu đã triển khai ứng dụng 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ó một 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 để tham gia 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 trong Mô-đun 0. Nếu chưa có, bạn có thể tải ứng dụng này xuống 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 đoạn mã tương tự như đoạn mã trong thư mục "FINISH" (HOÀN TẤT) của Mô-đun 15.

Thư mục của các tệp BẮT ĐẦU trong Mô-đun 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 rằng ứ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 bạn hoạt động (với đầu ra tương tự như bên dưới), bạn đã sẵn sàng thêm tính năng sử dụng 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 đáng kể nào đối với cấu hình ứng dụng, tuy nhiên, như đã đề cập trước đó, chúng tôi đang 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 có trên máy chủ App Engine và bạn có thể 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

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

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

Hỗ trợ nhập và Jinja2

Nhóm 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 nội dung thay đổi:

  1. Mục đích của mô-đun os là tạo tên đường dẫn tệp cho một mẫu Django. Vì chúng ta đang chuyển sang Jinja2 để xử lý việc này, nên không cần 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 ta sẽ xoá chúng.
  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ã bên dưới.

SAU:

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

Sau các lệnh 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 webapp2_extras. Đoạn mã sau đây bao bọc 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 các 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 chế độ 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 ta giữ nguyên chức năng hoặc đầu ra của ứng dụng mẫu (hoặc gần như giống nhau) mà không có (nhiều) thay đổi đối với trải nghiệm người dùng, ví dụ này có sự khác biệt lớn hơn so với thông thường. Thay vì ngay lập tức đăng ký 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 tôi đang cập nhật ứng dụng để yêu cầu người dùng cung cấp một tệp hiện vật để đăng ký lượt truy cập của họ. Sau đó, người dùng cuối có thể tải một tệp tương ứng lên hoặc chọn "Bỏ qua" để không tải bất kỳ 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 tôi sử dụng dịch vụ Blobstore để lưu trữ (và có thể sau này sẽ hiển thị) 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ữ nhiều dữ liệu hơn, 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 thông tin tham chiếu để lưu mã nhận dạng đó trong store_visit(). Vì dữ liệu bổ sung này được trả về cùng với mọi thứ 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, có sự xuất hiện của 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 đáng kể nhất về chức năng là hỗ trợ tải tệp lên, cho dù đó là lời nhắc người dùng về một tệp, hỗ trợ tính năng "bỏ qua" hay hiển thị một 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. Đây là những thay đổi bắt buộc để 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ị nữa. Thay vào đó, nó sẽ nhắc người dùng tải lên.
  2. Khi người dùng cuối gửi một tệp để tải lên hoặc bỏ qua quy trình đó, một POST trong biểu mẫu sẽ chuyển quyền kiểm soát cho 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 quá trình 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 quay lại "/", trong đó...
  4. Phương thức POST của trình xử lý chính sẽ 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. Phần hiển thị lượt truy cập gần đây nhất có một trường mới mà người dùng nhìn thấy, đó 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ó. Những thay đổi này được nhận ra trong mẫu HTML cùng với việc bổ sung một biểu mẫu tải lên (sẽ có thêm thông tin về vấn đề này trong thời gian tới).
  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 được tải lên, thì thao tác này sẽ tạo một yêu cầu GET đến 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 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 đường mới để gửi lưu lượng truy cập đến các lớp này, trình xử lý chính cần một phương thức POST mới để nhận lệnh chuyển hướng 307 như mô tả ở trên.

Trước những bản cập nhật này, ứng dụng Module 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 những nội dung cập nhật đó, hiện có 3 trình xử lý: 1) trình xử lý tải lên có phương thức POST, 2) trình xử lý tải xuống "xem blob" có phương thức GET và 3) trình xử lý chính có các phương thức GETPOST. Hãy thực hiện những thay đổi này để phần còn lại của ứng dụng có dạ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 ra URL mà biểu mẫu POSTs, 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ểm mấu chốt giúp đưa tệp vào Blobstore và trả về một mã nhận dạng duy nhất và lâu dài cho tệp đó, BlobKey.
  • Trong ViewBlobHandler.get, việc gọi blobstore_handlers.BlobstoreDownloadHandler.send bằng BlobKey của một 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 việc 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 bộ thay đổi thứ hai và cũng là bộ 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, thực tế là có 2 thay đổi:

  1. Bạn cần có biểu mẫu tải tệp lên với 3 phần tử đầu vào: một tệp và một cặp nút gửi để tải tệp lên và bỏ qua tương ứng.
  2. Cập nhật đầu ra 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 những lượt truy cập có tệp tải lên tương ứng hoặc "không có" nếu không.

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 thành mẫu mới cập nhật:

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

Một thay đổi cuối cùng là Jinja2 ưu tiên các mẫu của mình trong thư mục templates, vì vậy, hãy tạo thư mục đó và di chuyển index.html vào bên trong. 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 Mô-đun 0.

(không bắt buộc) "Nâng cao" 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 bảng điều khiển Cloud, cụ thể là trình duyệt Cloud Storage. Câu hỏi là ở đâu. Câu trả lời là vùng chứa Cloud Storage mặc định của ứng dụng App Engine. Tên của miền này là tên miền đầy đủ của ứng dụng App Engine, PROJECT_ID.appspot.com. Thật tiện lợi vì tất cả mã dự án đều là duy nhất, phải không?

Các nội dung cập nhật được thực hiện cho ứng dụng mẫu sẽ thả các tệp đã tải lên vào nhóm đó, 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 nhóm 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(), yêu cầu nhập mới nếu bạn muốn truy cập vào giá trị này, chẳng hạn như sử dụng làm tiền tố để 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 thao tác tương tự cho Hình ảnh, bạn sẽ có mã như thế này cùng với một số mã kiểm tra loại tệp để chọn tên nhóm 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 nên giới hạn kích thước của tệp tải lên trong trường hợp 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 vị trí lưu trữ các tệp đã tải lên? Điều quan trọng là bạn phải đ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 hoạt động 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 vị trí tải tệp 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 lựa chọn thay thế có tên là main-gcs.py trong kho lưu trữ. Thay vì sử dụng "thư mục" riêng biệt, mã trong main-gcs.py lưu trữ các tệp tải lên trong vùng 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 lấy mẫu thành một thứ gì đó khác như đã gợi ý trong phần này. Dưới đây là hình minh hoạ về "sự khác biệt" giữa main.pymain-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 bằng cách triển khai ứng dụng, xác minh rằng ứng dụng hoạt động như dự kiến và trong mọi đầu ra đượ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 rằng ứng dụng hoạt động như quảng cáo, khác biệt về trải nghiệm người dùng (UX) so với ứng dụng Mô-đun 0. Hiện có 2 màn hình 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 của lượt truy cập:

f5b5f9f19d8ae978.pngTừ đó, 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 bất kỳ nội dung 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 về 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 bằng cách thêm việc sử dụng Blobstore của App Engine vào ứng dụng mẫu Mô-đun 0. Giờ đây, mã của bạn sẽ 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 bị tính phí. Tuy nhiên, nếu muốn kiểm thử hoặc thử nghiệm thêm, nền tảng App Engine có một hạn mức miễn phí. Vì vậy, miễn là không vượt quá cấp sử dụng đó, bạn sẽ không bị tính phí. Đó là mức phí cho hoạt động tính toán, nhưng cũng có thể có các khoản phí cho các dịch vụ App Engine có liên quan. Vì vậy, hãy xem trang định giá của dịch vụ này để 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ụ đám mây khác, 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.

Để công bố đầy đủ, việc triển khai trê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 một khoản chi phí nhỏ cho việc tạo và lưu trữ. 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ẽ chiếm một phần hạn mức. Tuy nhiên, có thể bạn sinh sống ở một khu vực không có gói miễn phí như vậy, vì vậy, hãy lưu ý đến mức sử dụng bộ nhớ để giảm thiểu chi phí phát sinh. Bạn nên xem xét các "thư mục" cụ thể trên Cloud Storage, 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*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.

Cụ thể đối với lớp học lập trình này

Các dịch vụ trong danh sách dưới đây là riêng biệt đối với 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

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

Ngoài Mô-đun 16, còn có rất nhiều lựa chọn di chuyển khác, 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 trên nhiều sản phẩm sang Cloud Run và Cloud Functions. Kho lưu trữ di chuyển có tất cả các mẫu mã, đường liên kết đế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 cân nhắc và "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 gặp vấn đề với lớp học lập trình này, vui lòng tìm kiếm vấn đề của bạn trước khi 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 bên dưới. Bạn cũng có thể truy cập vào các hướng dẫn này trong kho lưu trữ cho tất cả các hoạt động di chuyển codelab 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

Module 0

code

Không có

Học phần 15 (lớp học lập trình này)

code

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.