网络钩子

网络钩子是托管业务逻辑的服务。在会话期间,Webhook 允许您使用 Dialogflow 的自然语言处理提取的数据来生成动态响应、验证收集的数据或在后端上触发操作。

CX 网络钩子与 ES 网络钩子类似,不同之处在于请求和响应字段进行了更改以支持 CX 功能。

网络钩子服务要求

您的网络钩子服务必须满足以下要求:

  • 它必须处理 HTTPS 请求。不支持 HTTP。如果您使用计算无服务器计算解决方案在 Google Cloud Platform 上托管您的 webhook 服务,请参阅使用 HTTPS 提供服务的产品文档。 如需了解其他托管选项,请参阅为您的网域获取 SSL 证书
  • 请求的网址必须可公开访问。
  • 它必须使用 JSON WebhookRequest 正文处理 POST 请求。
  • 它必须使用 JSON WebhookResponse 正文响应 WebhookRequest 请求。
  • 如果代理未与 Service Directory 专用网络访问通道集成,则网络钩子调用会被视为在服务边界外进行,并在启用 VPC Service Controls 时被屏蔽。 Service Directory 支持有限的端点;如需了解详情,请参阅 Service Directory

身份验证

请务必保护您的网络钩子服务,以便只有您或 Dialogflow 代理有权发出请求。这是在创建 Webhook 资源时配置的。Dialogflow CX 支持以下身份验证机制:

HTTPS 证书验证

默认情况下,Dialogflow 使用 Google 的默认信任库来验证 HTTPS 证书。如果您打算将 HTTPS 服务器无法识别的 Google 默认证书存储区(例如自签名证书或自定义根证书)使用,请参阅自定义 CA 证书

网络钩子请求

调用具有网络钩子的 fulfillment 时,Dialogflow 会向您的网络钩子服务发送 HTTPS POST 网络钩子请求。此请求的正文是一个 JSON 对象,其中包含有关匹配 intent 的信息。

如需了解详情,请参阅 WebhookRequest(V3)WebhookRequest(V3Beta1) 参考文档。

网络钩子响应

网络钩子服务收到网络钩子请求后,需要发送网络钩子响应。您的响应会受到以下限制:

  • 响应必须在您在创建网络钩子资源时配置的超时时间内进行,否则请求会超时。
  • 响应大小必须小于或等于 64 KiB。

如需了解详情,请参阅 WebhookResponse(V3)WebhookResponse(V3Beta1) 参考文档。

创建网络钩子资源

在运行 Webhook 服务后,您需要在代理中创建具有连接和身份验证信息的 Webhook 资源。如需创建网络钩子资源,请执行以下操作:

控制台

  1. 打开 Dialogflow CX 控制台
  2. 选择您的 GCP 项目。
  3. 选择您的代理。
  4. 选择管理标签页。
  5. 点击 Webhook
  6. 点击创建
  7. 输入网络钩子数据。
  8. 点击保存

API

请参阅 Webhook 类型的 create 方法。

为 Webhook 参考选择协议和版本

协议 版本 3 V3beta1
REST 网络钩子资源 网络钩子资源
远程过程调用 (RPC) 网络钩子界面 网络钩子界面
C# 不可用 不可用
转到 不可用 不可用
Java WebhooksClient WebhooksClient
Node.js WebhooksClient WebhooksClient
PHP 不可用 不可用
Python WebhooksClient WebhooksClient
Ruby 不可用 不可用

网络钩子错误

如果您的网络钩子服务在处理网络钩子请求时遇到错误,那么您的网络钩子代码应返回以下某个 HTTP 状态代码:

  • 400请求有误
  • 401 未经授权
  • 403 已禁止
  • 找不到“404
  • 500 服务器故障
  • 503服务不可用

在以下任何一种错误情况下,Dialogflow 都会调用网络钩子错误或超时内置事件,并照常处理:

  • 响应超时。
  • 已收到错误状态代码。
  • 响应无效。
  • 网络钩子服务不可用。

此外,如果检测意图 API 调用触发了网络钩子服务调用,则检测意图响应中的 queryResult.webhookStatuses 字段将包含网络钩子状态信息。

使用 Cloud Functions

Dialogflow 与 Cloud Functions 相集成,因此您可以轻松创建安全的无服务器 Webhook。 如果您创建的函数与代理位于同一项目中,则代理可以安全地调用网络钩子,而无需任何特殊配置。

不过,在以下两种情况下,您必须手动设置此集成:

  1. 您的代理项目必须存在具有以下地址的 Dialogflow Service Agent 服务帐号
    service-agent-project-number@gcp-sa-dialogflow.iam.gserviceaccount.com
    当您为项目创建第一个代理时,系统会自动创建此特殊服务帐号和关联的密钥。如果代理是在 2020 年 11 月 1 日之前创建的,则可以触发此特殊服务帐号的创建:
    1. 为项目创建新的代理。
    2. 执行以下命令:
      gcloud beta services identity create --service=dialogflow.googleapis.com --project=agent-project-id
  2. 如果您的网络钩子函数与代理位于不同的项目中,则您必须向函数项目中的 Dialogflow Service Agent 服务帐号提供 Cloud Functions Invoker IAM 角色

使用 Service Directory 进行专用网络访问

Dialogflow 与 Service Directory 专用网络访问通道集成,因此可以连接到 VPC 网络内的 Webhook 目标。这样可以将流量保留在 Google Cloud 网络中,并实施 IAMVPC Service Controls

如需设置以专用网络为目标的网络钩子,请执行以下操作:

  1. 按照 Service Directory 专用网络配置,配置您的 VPC 网络和 Service Directory 端点。
  2. 您的代理项目必须存在具有以下地址的 Dialogflow Service Agent 服务帐号
    service-agent-project-number@gcp-sa-dialogflow.iam.gserviceaccount.com
    Dialogflow Service Agent 服务帐号授予以下 IAM 角色:
    • Service Directory 项目的 servicedirectory.viewer
    • 网络项目的 servicedirectory.pscAuthorizedService
  3. 在创建网络钩子时,提供 Service Directory Service 以及网址和可选的身份验证信息。

    控制台

    Service Directory Webhook 屏幕截图。

    API

    请参阅 Webhook 类型的 serviceDirectory 字段。

    为 Webhook 参考选择协议和版本

    协议 版本 3 V3beta1
    REST 网络钩子资源 网络钩子资源
    远程过程调用 (RPC) 网络钩子界面 网络钩子界面
    C# 不可用 不可用
    转到 不可用 不可用
    Java WebhooksClient WebhooksClient
    Node.js WebhooksClient WebhooksClient
    PHP 不可用 不可用
    Python WebhooksClient WebhooksClient
    Ruby 不可用 不可用

服务身份令牌

Dialogflow 调用网络钩子时,会在请求中提供 Google 身份令牌。任何网络钩子都可以选择性地使用 Google 客户端库或 github.com/googleapis/google-auth-library-nodejs 等开源库来验证令牌。例如,您可以按以下形式验证 ID 令牌的 email

service-agent-project-number@gcp-sa-dialogflow.iam.gserviceaccount.com

示例

以下示例展示了如何接收 WebhookRequest 和发送 WebhookResponse。

Java


// TODO: Change class name to Example
// TODO: add GSON dependency to Pom file
// (https://mvnrepository.com/artifact/com.google.code.gson/gson/2.8.5)
// TODO: Uncomment the line bellow before running cloud function
// package com.example;

import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.BufferedWriter;

public class BasicWebhook implements HttpFunction {
  @Override
  public void service(HttpRequest request, HttpResponse response) throws Exception {
    JsonParser parser = new JsonParser();
    Gson gson = new GsonBuilder().create();
    JsonObject parsedRequest = gson.fromJson(request.getReader(), JsonObject.class);

    // For more information on the structure of this object https://cloud.google.com/dialogflow/cx/docs/reference/rest/v3/Fulfillment
    String requestTag = parsedRequest.getAsJsonObject("fulfillmentInfo")
        .getAsJsonPrimitive("tag").toString();
    JsonObject responseObject = null;
    String defaultIntent = "\"Default Welcome Intent\"";
    String secondIntent = "\"get-agent-name\"";
    String responseText = "";

    // Compares the Intent Tag to provide the correct response
    if (requestTag.equals(defaultIntent)) {
      responseText = "\"Hello from a Java GCF Webhook\"";
    } else if (requestTag.equals(secondIntent)) {
      responseText = "\"My name is Flowhook\"";
    } else {
      responseText = "\"Sorry I didn't get that\"";
    }

    // Constructing the response jsonObject
    responseObject =
        parser
            .parse(
                "{ \"fulfillment_response\": { \"messages\": [ { \"text\": { \"text\": ["
                    + responseText
                    + "] } } ] } }")
            .getAsJsonObject();
    BufferedWriter writer = response.getWriter();

    //Sends the responseObject
    writer.write(responseObject.toString());
  }
}

Node.js


// TODO: change entry point to exports.handleWebhook in cloud function

exports.handleWebhook = (request, response) => {
  const tag = request.body.fulfillmentInfo.tag;
  let text = '';

  if (tag === 'Default Welcome Intent') {
    text = 'Hello from a GCF Webhook';
  } else if (tag === 'get-name') {
    text = 'My name is Flowhook';
  } else {
    text = `There are no fulfillment responses defined for "${tag}"" tag`;
  }

  const jsonResponse = {
    fulfillment_response: {
      messages: [
        {
          text: {
            //fulfillment text response to be sent to the agent
            text: [text],
          },
        },
      ],
    },
  };

  response.send(jsonResponse);
};

Python


# TODO(developer): change entry point to handle_webhook in cloud function

def handle_webhook(request):

    req = request.get_json()

    tag = req["fulfillmentInfo"]["tag"]

    if tag == "Default Welcome Intent":
        # You can also use the google.cloud.dialogflowcx_v3.types.WebhookRequest protos instead of manually writing the json object
        # Please see https://googleapis.dev/python/dialogflow/latest/dialogflow_v2/types.html?highlight=webhookresponse#google.cloud.dialogflow_v2.types.WebhookResponse for an overview
        res = {
            "fulfillment_response": {
                "messages": [{"text": {"text": ["Hi from a GCF Webhook"]}}]
            }
        }
    elif tag == "get-name":
        res = {
            "fulfillment_response": {
                "messages": [{"text": {"text": ["My name is Phlowhook"]}}]
            }
        }
    else:
        res = {
            "fulfillment_response": {
                "messages": [
                    {
                        "text": {
                            "text": [
                                f"There are no fulfillment responses defined for {tag} tag"
                            ]
                        }
                    }
                ]
            }
        }

    # Returns json
    return res