Thiết lập và nhận thông báo đẩy

Bạn có thể sử dụng các phương thức trong bộ sưu tập Watches (Đồng hồ) để nhận thông báo khi dữ liệu thay đổi trong biểu mẫu. Trang này cung cấp thông tin tổng quan và hướng dẫn về cách thiết lập và nhận thông báo đẩy.

Tổng quan

Tính năng thông báo đẩy của API Google Biểu mẫu cho phép các ứng dụng đăng ký nhận thông báo khi dữ liệu thay đổi trong biểu mẫu. Thông báo sẽ được gửi đến một chủ đề trên Cloud Pub/Sub, thường trong vòng vài phút kể từ khi có thay đổi.

Để nhận thông báo đẩy, bạn cần thiết lập chủ đề Cloud Pub/Sub và cung cấp tên của chủ đề đó khi tạo đồng hồ cho loại sự kiện thích hợp.

Dưới đây là định nghĩa về các khái niệm chính được sử dụng trong tài liệu này:

  • Mục tiêu là nơi gửi thông báo. Mục tiêu duy nhất được hỗ trợ là chủ đề Cloud Pub/Sub.
  • Loại sự kiện là một danh mục thông báo mà ứng dụng bên thứ ba có thể đăng ký.
  • Đồng hồ là hướng dẫn cho API Biểu mẫu để gửi thông báo về một loại sự kiện cụ thể trên một biểu mẫu cụ thể tới một mục tiêu.

Sau khi bạn tạo đồng hồ cho một loại sự kiện trên một biểu mẫu cụ thể, mục tiêu của đồng hồ đó (chủ đề Cloud Pub/Sub) sẽ nhận được thông báo từ các sự kiện đó trên biểu mẫu đó cho đến khi đồng hồ hết hạn. Đồng hồ của bạn có thể dùng trong một tuần, nhưng bạn có thể gia hạn thời gian này bất cứ lúc nào trước khi hết hạn bằng cách gửi yêu cầu tới watches.renew().

Chủ đề Cloud Pub/Sub của bạn chỉ nhận được thông báo về các biểu mẫu mà bạn có thể xem bằng thông tin xác thực mà bạn cung cấp. Ví dụ: nếu người dùng thu hồi quyền trong ứng dụng hoặc mất quyền chỉnh sửa một biểu mẫu đã xem, thì thông báo sẽ không được gửi nữa.

Các loại sự kiện hiện có

API Google Biểu mẫu hiện cung cấp hai danh mục sự kiện:

  • EventType.SCHEMA – thông báo về các nội dung chỉnh sửa đối với nội dung và chế độ cài đặt của biểu mẫu.
  • EventType.RESPONSES – sẽ thông báo khi bạn gửi phản hồi qua biểu mẫu (cả mới và cập nhật).

Phản hồi thông báo

Thông báo được mã hoá bằng JSON và chứa:

  • Mã của biểu mẫu kích hoạt
  • Mã của đồng hồ đang kích hoạt
  • Loại sự kiện đã kích hoạt thông báo
  • Các trường khác do Cloud Pub/Sub đặt, chẳng hạn như messageIdpublishTime

Thông báo không chứa dữ liệu chi tiết về biểu mẫu hoặc phản hồi. Sau khi nhận được mỗi thông báo, bạn cần có một lệnh gọi API riêng để tìm nạp dữ liệu mới. Hãy xem phần Cách sử dụng đề xuất để biết cách thực hiện việc này.

Đoạn mã sau đây minh hoạ thông báo mẫu về việc thay đổi giản đồ:

{
  "attributes": {
    "eventType": "SCHEMA",
    "formId": "18Xgmr4XQb-l0ypfCNGQoHAw2o82foMr8J0HPHdagS6g",
    "watchId": "892515d1-a902-444f-a2fe-42b718fe8159"
  },
  "messageId": "767437830649",
  "publishTime": "2021-03-31T01:34:08.053Z"
}

Đoạn mã sau đây minh hoạ thông báo mẫu cho phản hồi mới:

{
  "attributes": {
    "eventType": "RESPONSES",
    "formId": "18Xgmr4XQb-l0ypfCNGQoHAw2o82foMr8J0HPHdagS6g",
    "watchId": "5d7e5690-b1ff-41ce-8afb-b469912efd7d"
  },
  "messageId": "767467004397",
  "publishTime": "2021-03-31T01:43:57.285Z"
}

Thiết lập chủ đề Cloud Pub/Sub

Thông báo được gửi đến các chủ đề trên Cloud Pub/Sub. Trên Cloud Pub/Sub, bạn có thể nhận thông báo trên một webhook hoặc bằng cách thăm dò điểm cuối của gói thuê bao.

Để thiết lập chủ đề Cloud Pub/Sub, hãy làm như sau:

  1. Hoàn thành Điều kiện tiên quyết về Cloud Pub/Sub.
  2. Thiết lập máy khách Cloud Pub/Sub.
  3. Xem lại giá của Cloud Pub/Sub và bật tính năng thanh toán cho dự án Developer Console của bạn.
  4. Tạo chủ đề Cloud Pub/Sub bằng một trong ba cách:

  5. Tạo Gói thuê bao trong Cloud Pub/Sub để cho Cloud Pub/Sub biết cách gửi thông báo của bạn.

  6. Cuối cùng, trước khi tạo đồng hồ nhắm mục tiêu đến chủ đề của mình, bạn cần cấp quyền cho tài khoản dịch vụ thông báo của Biểu mẫu (forms-notifications@system.gserviceaccount.com) để xuất bản chủ đề.

Tạo đồng hồ

Sau khi có chủ đề mà tài khoản dịch vụ thông báo đẩy của API Biểu mẫu có thể phát hành, bạn có thể tạo thông báo bằng phương thức watches.create(). Phương thức này xác thực rằng chủ đề Cloud Pub/Sub đã cung cấp có thể truy cập được qua tài khoản dịch vụ thông báo đẩy và sẽ không truy cập được nếu không truy cập được chủ đề này; ví dụ: nếu chủ đề không tồn tại hoặc bạn chưa cấp quyền phát hành cho chủ đề đó.

Python

forms/snippets/create_watch.py
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools

SCOPES = "https://www.googleapis.com/auth/drive"
DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"

store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
  flow = client.flow_from_clientsecrets("client_secret.json", SCOPES)
  creds = tools.run_flow(flow, store)

service = discovery.build(
    "forms",
    "v1",
    http=creds.authorize(Http()),
    discoveryServiceUrl=DISCOVERY_DOC,
    static_discovery=False,
)

watch = {
    "watch": {
        "target": {"topic": {"topicName": "<YOUR_TOPIC_PATH>"}},
        "eventType": "RESPONSES",
    }
}

form_id = "<YOUR_FORM_ID>"

# Print JSON response after form watch creation
result = service.forms().watches().create(formId=form_id, body=watch).execute()
print(result)

Node.js

forms/snippets/create_watch.js
'use strict';

const path = require('path');
const google = require('@googleapis/forms');
const {authenticate} = require('@google-cloud/local-auth');

const formID = '<YOUR_FORM_ID>';

async function runSample(query) {
  const authClient = await authenticate({
    keyfilePath: path.join(__dirname, 'credentials.json'),
    scopes: 'https://www.googleapis.com/auth/drive',
  });
  const forms = google.forms({
    version: 'v1',
    auth: authClient,
  });
  const watchRequest = {
    watch: {
      target: {
        topic: {
          topicName: 'projects/<YOUR_TOPIC_PATH>',
        },
      },
      eventType: 'RESPONSES',
    },
  };
  const res = await forms.forms.watches.create({
    formId: formID,
    requestBody: watchRequest,
  });
  console.log(res.data);
  return res.data;
}

if (module === require.main) {
  runSample().catch(console.error);
}
module.exports = runSample;

Xoá đồng hồ

Python

forms/snippets/delete_watch.py
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools

SCOPES = "https://www.googleapis.com/auth/drive"
DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"

store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
  flow = client.flow_from_clientsecrets("client_secret.json", SCOPES)
  creds = tools.run_flow(flow, store)
service = discovery.build(
    "forms",
    "v1",
    http=creds.authorize(Http()),
    discoveryServiceUrl=DISCOVERY_DOC,
    static_discovery=False,
)

form_id = "<YOUR_FORM_ID>"
watch_id = "<YOUR_WATCH_ID>"

# Print JSON response after deleting a form watch
result = (
    service.forms().watches().delete(formId=form_id, watchId=watch_id).execute()
)
print(result)

Node.js

biểu mẫu/đoạn mã/delete_watch.js
'use strict';

const path = require('path');
const google = require('@googleapis/forms');
const {authenticate} = require('@google-cloud/local-auth');

const formID = '<YOUR_FORM_ID>';
const watchID = '<YOUR_FORMS_WATCH_ID>';

async function runSample(query) {
  const authClient = await authenticate({
    keyfilePath: path.join(__dirname, 'credentials.json'),
    scopes: 'https://www.googleapis.com/auth/drive',
  });
  const forms = google.forms({
    version: 'v1',
    auth: authClient,
  });
  const res = await forms.forms.watches.delete({
    formId: formID,
    watchId: watchID,
  });
  console.log(res.data);
  return res.data;
}

if (module === require.main) {
  runSample().catch(console.error);
}
module.exports = runSample;

Ủy quyền

Giống như mọi lệnh gọi đến API Biểu mẫu, các lệnh gọi đến watches.create() phải được uỷ quyền bằng mã thông báo uỷ quyền. Mã thông báo phải bao gồm một phạm vi cấp quyền đọc dữ liệu về những thông báo đang được gửi.

Để gửi thông báo, ứng dụng phải giữ lại thông tin đã cấp OAuth từ người dùng được uỷ quyền trong các phạm vi bắt buộc. Nếu người dùng ngắt kết nối ứng dụng, thì thông báo sẽ dừng lại và đồng hồ có thể bị tạm ngưng do xảy ra lỗi. Để tiếp tục nhận thông báo sau khi được cấp lại quyền, hãy xem phần Gia hạn đồng hồ.

Liệt kê đồng hồ của một biểu mẫu

Python

form/snippets/list_watches.py
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools

SCOPES = "https://www.googleapis.com/auth/drive"
DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"

store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
  flow = client.flow_from_clientsecrets("client_secrets.json", SCOPES)
  creds = tools.run_flow(flow, store)
service = discovery.build(
    "forms",
    "v1",
    http=creds.authorize(Http()),
    discoveryServiceUrl=DISCOVERY_DOC,
    static_discovery=False,
)

form_id = "<YOUR_FORM_ID>"

# Print JSON list of form watches
result = service.forms().watches().list(formId=form_id).execute()
print(result)

Node.js

form/snippets/list_watches.js (biểu mẫu/đoạn mã/list_watches.js)
'use strict';

const path = require('path');
const google = require('@googleapis/forms');
const {authenticate} = require('@google-cloud/local-auth');

const formID = '<YOUR_FORM_ID>';

async function runSample(query) {
  const auth = await authenticate({
    keyfilePath: path.join(__dirname, 'credentials.json'),
    scopes: 'https://www.googleapis.com/auth/forms.responses.readonly',
  });
  const forms = google.forms({
    version: 'v1',
    auth: auth,
  });
  const res = await forms.forms.watches.list({formId: formID});
  console.log(res.data);
  return res.data;
}

if (module === require.main) {
  runSample().catch(console.error);
}
module.exports = runSample;

Gia hạn đồng hồ

Python

forms/snippets/renew_watch.py
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools

SCOPES = "https://www.googleapis.com/auth/drive"
DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"

store = file.Storage("token.json")
creds = None
if not creds or creds.invalid:
  flow = client.flow_from_clientsecrets("client_secrets.json", SCOPES)
  creds = tools.run_flow(flow, store)
service = discovery.build(
    "forms",
    "v1",
    http=creds.authorize(Http()),
    discoveryServiceUrl=DISCOVERY_DOC,
    static_discovery=False,
)

form_id = "<YOUR_FORM_ID>"
watch_id = "<YOUR_WATCH_ID>"

# Print JSON response after renewing a form watch
result = (
    service.forms().watches().renew(formId=form_id, watchId=watch_id).execute()
)
print(result)

Node.js

biểu mẫu/đoạn mã/renew_watch.js
'use strict';

const path = require('path');
const google = require('@googleapis/forms');
const {authenticate} = require('@google-cloud/local-auth');

const formID = '<YOUR_FORM_ID>';
const watchID = '<YOUR_FORMS_WATCH_ID>';

async function runSample(query) {
  const authClient = await authenticate({
    keyfilePath: path.join(__dirname, 'credentials.json'),
    scopes: 'https://www.googleapis.com/auth/drive',
  });
  const forms = google.forms({
    version: 'v1',
    auth: authClient,
  });
  const res = await forms.forms.watches.renew({
    formId: formID,
    watchId: watchID,
  });
  console.log(res.data);
  return res.data;
}

if (module === require.main) {
  runSample().catch(console.error);
}
module.exports = runSample;

Điều tiết

Thông báo bị điều tiết – mỗi đồng hồ có thể nhận được tối đa một thông báo sau mỗi 30 giây. Ngưỡng tần suất này có thể thay đổi.

Do tính năng điều tiết, một thông báo có thể tương ứng với nhiều sự kiện. Nói cách khác, thông báo cho biết một hoặc nhiều sự kiện đã xảy ra kể từ thông báo gần nhất.

Các giới hạn

Tại mọi thời điểm, đối với một biểu mẫu và loại sự kiện nhất định, mỗi dự án Cloud Console có thể có:

  • tổng cộng tối đa 20 đồng hồ
  • tối đa một đồng hồ cho mỗi người dùng cuối

Ngoài ra, bất cứ lúc nào, mỗi biểu mẫu chỉ được có tối đa 50 đồng hồ cho mỗi loại sự kiện, đối với tất cả các dự án Cloud Console.

Đồng hồ được liên kết với người dùng cuối khi được tạo hoặc gia hạn bằng thông tin đăng nhập cho người dùng đó. Đồng hồ sẽ bị tạm ngưng nếu người dùng cuối được liên kết mất quyền truy cập vào biểu mẫu hoặc thu hồi quyền truy cập của ứng dụng vào biểu mẫu.

Độ tin cậy

Mỗi đồng hồ sẽ được thông báo ít nhất một lần sau mỗi sự kiện trong mọi trường hợp đặc biệt. Trong hầu hết các trường hợp, thông báo sẽ được gửi trong vòng vài phút sau khi sự kiện diễn ra.

Lỗi

Nếu thông báo của đồng hồ liên tục không được gửi, trạng thái đồng hồ sẽ trở thành SUSPENDED và trường errorType của đồng hồ được đặt. Để đặt lại trạng thái của đồng hồ bị tạm ngưng thành ACTIVE và tiếp tục nhận thông báo, hãy xem phần Gia hạn đồng hồ.

Cách sử dụng được đề xuất

  • Sử dụng một chủ đề Cloud Pub/Sub duy nhất làm mục tiêu của nhiều lượt theo dõi.
  • Khi nhận được thông báo về một chủ đề, mã biểu mẫu sẽ được đưa vào trọng tải thông báo. Hãy sử dụng sự kiện này với loại sự kiện để biết dữ liệu nào cần tìm nạp và biểu mẫu nào cần tìm nạp.
  • Để tìm nạp dữ liệu cập nhật sau khi có thông báo bằng EventType.RESPONSES, hãy gọi forms.responses.list().
    • Đặt bộ lọc theo yêu cầu thành timestamp > timestamp_of_the_last_response_you_fetched.
  • Để tìm nạp dữ liệu cập nhật sau khi nhận được thông báo bằng EventType.SCHEMA, hãy gọi forms.get().