首页 > 解决方案 > cMalformedResponse: Webhook 错误 (206) 而看似有效的 Webhook 响应 - Node.js 中 Google Dialogflow 应用程序上的操作

问题描述

问题

我正在通过 Dialogflow 使用托管在 Firebase Google Functions 上的 Node.js 的 Actions on Google 应用程序开发一个 Actions on Google 应用程序(用于 Google Home)。我经常但不定期地(并且难以复制)遇到错误,迫使 Google 上的操作(模拟器或 Google Home 本身)关闭我的应用程序。我将所有 Dialogflow 意图(包括回退)路由到我的 webhook 实现,并且 - 基于日志文件 - webhook 快速响应(在 ~200 毫秒内)并具有有效响应(调查 JSON 响应)。但是,Actions on Google 似乎拒绝响应并触发 Dialogflow 默认文本响应。我最担心的是,它发生在对话的不同阶段,有时已经在欢迎活动中。还值得注意的是 - 即使履行以毫秒(〜200)响应,Google / Dialogflow 上的操作也需要时间并且 - 我相信 - 有超时。以下是我对潜在原因的探索。但坦率地说,我没有想法。

- 编辑 -

该服务现在似乎运行得更好 - 我没有遇到这个错误。通过使用全局数据库并将其传递,我已更改代码以减少调用 admin.firestore() 的频率。我有一种预感,可能同时调用了 https 函数,这可能会以某种方式导致格式错误的响应。

const database = admin.firestore();

// code

if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === 'functionname') {
 exports.functionname = functions.https.onRequest((req, res) => {
    require('./functions').functionname(req, res, database);
 });
}

我还在我的意图处理中发现了一个缺陷,导致没有匹配的意图。我已经重组了 Dialogflow 意图,以减少这种无意图的可能性(我基本上做了一个两步问题来确定用户的意图)。但是,由于 webhook 确实响应正确,我不认为这是问题所在。不过,我觉得这是一个奇怪的错误——所以如果有人有更多的指点,请!

-- 结束编辑 --

日志

这是从 Google Functions Log 中看到的来自 webhook 的响应 - 表示向 Dialogflow 应用程序发送响应。

Function execution took 289 ms, finished with status code: 200 

Response {
  "status": 200,
  "headers": {
    "content-type": "application/json;charset=utf-8"
  },
  "body": {
    "payload": {
      "google": {
        "expectUserResponse": true,
        "richResponse": {
          "items": [{
            "simpleResponse": {
              "textToSpeech": "Welcome back! Which Widget do you want to work with?"
            }
          }]
        }
      }
    },
    "outputContexts": [{
        "name": "****anonymized****/contexts/widget",
        "lifespanCount": 1
      },
      {
        "name": "***anonymized****/contexts/_actions_on_google",
        "lifespanCount": 99,
        "parameters": {
          "data": "{\"started\":1552071670}"
        }
      }
    ]
  }
}

但是,这就是 Actions on Google 控制台所显示的内容。textToSpeech 响应是默认文本响应,如果执行失败,DialogFlow 可以回退到该响应(如https://medium.com/google-developers/debugging-common-actions-on-google-errors-7c8527378d27建议的那样)

{
  "conversationToken": "[]",
  "finalResponse": {
    "richResponse": {
      "items": [
        {
          "simpleResponse": {
            "textToSpeech": "Sorry! I cannot access my online service. Please try again!"
          }
        }
      ]
    }
  },
  "responseMetadata": {
    "status": {
      "code": 14,
      "message": "Webhook error (206)"
    },
    "queryMatchInfo": {
      "queryMatched": true,
      "intent": "e0bf4b96-9440-4545-a8a6-d0915cacd34f"
    }
  }
}

堆栈驱动程序日志还指示后一种情况,即收到来自 Dialogflow 的默认响应。

想法

我试图在模拟器、手机和 Google Home 上复制此错误。它发生在不同的时刻,尽管似乎比以前更频繁地发生。我的三个预感如下:

  1. 超载。我的 Google Functions 包含 8 个函数,包括 Dialogflow 应用程序。也许如果在给定时刻也经常调用其​​他函数,那么处理来自 Dialogflow(Google 助手)的 https 请求的 Dialogflow 应用程序会出现问题。但是,我不明白这应该如何发生。我可以通过在具有两个不同帐户的两台设备上调用该应用程序来复制(有时)该问题。但由于它也发生在一个帐户上,我认为这不是唯一的问题。我已按照此提示减少过载(https://stackoverflow.com/a/47985480/7053198),但这似乎对我的问题没有帮助。那么,Google Functions 的升级会成为问题吗?
  2. 承诺地狱。我正在使用许多承诺(或更多回调)与 Firestore 数据库通信以检索用户数据。但是,我可以非常快速地调用这些意图,并且它们很好地解决了 - 直到它们没有解决的地步。下面是这样一个意图的片段。
  3. 我的应用程序的大小。Intent 的数量变得相当大,Google Functions 和 Firestore 数据库之间有很多通信。我只是不知道这会如何影响 Dialogflow 拒绝看似正确的响应。

带有承诺片段的意图:

app.intent(I.WIDGETTEST, conv => {
  let database = admin.firestore();
  let offline = [];

  return database.collection('users').doc(conv.user.storage.userId).collection('widgets').get()
  .then((snapshot) => { 

    const promises = [];
    snapshot.forEach(doc => {
      if (doc.data().active) {
        if ((moment().unix()-doc.data().server.seen) > 360){
          offline.push(doc.data().name);
        }
        promises.push(doc.ref.update({'todo.test': true}));
      }
    });
    return Promise.all(promises);
  })
  .then(()=>{
    conv.contexts.set(C.WIDGET, 1);
    return conv.ask("Testing in progress. Which Widget do you want to work with now?");
  })
  .catch((err) => {
    console.log(err)
    throw err;
  });
});

问题示例日志

为了更好地衡量,这里有来自堆栈驱动程序方面的三个日志条目:

{
    "textPayload": "Sending request with post data: {\"user\":{\"userId\":\"***anonymized***\",\"locale\":\"en-US\",\"lastSeen\":\"2019-03-08T18:54:47Z\",\"userStorage\":\"{\\\"data\\\":{\\\"userId\\\":\\\"***anonymized***\\\"}}\",\"idToken\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImNmMDIyYTQ5ZTk3ODYxNDhhZDBlMzc5Y2M4NTQ4NDRlMzZjM2VkYzEiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJuYmYiOjE1NTIwNzEzNjAsImF1ZCI6Ijk4NzgxNjU4MTIzMC1ibWVtMm5wcTRsNnE3c2I5MnVpM3BkdGRhMWFmajJvNy5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsInN1YiI6IjEwMjk3OTk3NzIyNTM3NjY4MDEyOSIsImVtYWlsIjoiZGF2aWR2ZXJ3ZWlqQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoiRCBWZXJ3ZWlqIiwicGljdHVyZSI6Imh0dHBzOi8vbGg2Lmdvb2dsZXVzZXJjb250ZW50LmNvbS8taldtOFd3eE5iS3MvQUFBQUFBQUFBQUkvQUFBQUFBQUFyLUUvNEE2UmJiYVNwem8vczk2LWMvcGhvdG8uanBnIiwiZ2l2ZW5fbmFtZSI6IkQiLCJmYW1pbHlfbmFtZSI6IlZlcndlaWoiLCJpYXQiOjE1NTIwNzE2NjAsImV4cCI6MTU1MjA3NTI2MCwianRpIjoiYjE4MDYwMjc0YmE4MjJhYzFhYzc0MTYwZjI2YWM2MDk3MzBmZDY4ZSJ9.Y9G0qo0Gf28-noF7RYPhtfHRuA7Qo6bCBSuN56Y0AtgIXaQKZjnmYvABIt9u8WQ1qPWwQc3jOLyhfoXIk8j0zhcQ0M0oc7LjkBwVCgFnJHvUAiV5fGEqQa95pZyrZhYmHipTDdwk0UhJHFGJOXAHDPP6oBSHKC9h48jqUjVszz6iEy4frV0XIKIzRR2U2iY6OgJuxPsV0A7xNjvLXiMmwaRUVtlj9CPmiizd3G2PhqD5C54Fy2Qg5ch89qMOA10vNB5B4AX9pmAXHpmtIqFo7ljvAeGAj-pRuqyMllz2awAdvqqOFRERDYfm5Fyh7N0l1OhR2A2XRegsUIL1I1EVPQ\"},\"conversation\":{\"conversationId\":\"ABwppHH8PXibDZg8in1DjbP-caFy67Dtq025k_Uq2ofoPNXKtiPXrbJTmpGVUnVy-aY6H1MeZCFIpQ\",\"type\":\"NEW\"},\"inputs\":[{\"intent\":\"actions.intent.MAIN\",\"rawInputs\":[{\"inputType\":\"KEYBOARD\",\"query\":\"Talk to ***anonymized appname***\"}]}],\"surface\":{\"capabilities\":[{\"name\":\"actions.capability.SCREEN_OUTPUT\"},{\"name\":\"actions.capability.MEDIA_RESPONSE_AUDIO\"},{\"name\":\"actions.capability.AUDIO_OUTPUT\"},{\"name\":\"actions.capability.WEB_BROWSER\"}]},\"isInSandbox\":true,\"availableSurfaces\":[{\"capabilities\":[{\"name\":\"actions.capability.SCREEN_OUTPUT\"},{\"name\":\"actions.capability.AUDIO_OUTPUT\"},{\"name\":\"actions.capability.WEB_BROWSER\"}]}],\"requestType\":\"SIMULATOR\"}.",
    "insertId": "120zsprg2nqfayb",
    "resource": {
      "type": "assistant_action",
      "labels": {
        "action_id": "actions.intent.MAIN",
        "project_id": "***anonymized***",
        "version_id": ""
      }
    },
    "timestamp": "2019-03-08T19:01:00.243055001Z",
    "severity": "DEBUG",
    "labels": {
      "channel": "preview",
      "source": "AOG_REQUEST_RESPONSE",
      "querystream": "GOOGLE_USER"
    },

{
    "textPayload": "Received response from agent with body: HTTP/1.1 200 OK\r\nServer: nginx/1.13.6\r\nDate: Fri, 08 Mar 2019 19:01:10 GMT\r\nContent-Type: application/json;charset=UTF-8\r\nContent-Length: 330\r\nX-Cloud-Trace-Context: 7761b69610701e0a7d18cbc69eef9bde/3001560133061614360;o=0\r\nGoogle-Actions-API-Version: 2\r\nAccess-Control-Allow-Credentials: true\r\nVia: 1.1 google\r\nAlt-Svc: clear\r\n\r\n{\"conversationToken\":\"[]\",\"finalResponse\":{\"richResponse\":{\"items\":[{\"simpleResponse\":{\"textToSpeech\":\"Sorry! I cannot access my online service. Please try again!\"}}]}},\"responseMetadata\":{\"status\":{\"code\":14,\"message\":\"Webhook error (206)\"},\"queryMatchInfo\":{\"queryMatched\":true,\"intent\":\"e0bf4b96-9440-4545-a8a6-d0915cacd34f\"}}}.",
    "insertId": "120zsprg2nqfayc",
    "resource": {
      "type": "assistant_action",
      "labels": {
        "project_id": "***anonymized***",
        "version_id": "",
        "action_id": "actions.intent.MAIN"
      }
    },
    "timestamp": "2019-03-08T19:01:10.376894030Z",
    "severity": "DEBUG",
    "labels": {
      "channel": "preview",
      "source": "AOG_REQUEST_RESPONSE",
      "querystream": "GOOGLE_USER"
    },
    "logName": "projects/***anonymized***/logs/actions.googleapis.com%2Factions",
    "trace": "projects/987816581230/traces/ABwppHH8PXibDZg8in1DjbP-caFy67Dtq025k_Uq2ofoPNXKtiPXrbJTmpGVUnVy-aY6H1MeZCFIpQ",
    "receiveTimestamp": "2019-03-08T19:01:10.389139428Z"
  },
{
    "textPayload": "MalformedResponse: Webhook error (206)",
    "insertId": "1d4bzl9g3lossug",
    "resource": {
      "type": "assistant_action",
      "labels": {
        "project_id": "***anonymized***",
        "version_id": "",
        "action_id": "actions.intent.MAIN"
      }
    },
    "timestamp": "2019-03-08T19:01:10.377231474Z",
    "severity": "ERROR",
    "labels": {
      "channel": "preview",
      "source": "JSON_RESPONSE_VALIDATION",
      "querystream": "GOOGLE_USER"
    },
    "logName": "projects/***anonymized***/logs/actions.googleapis.com%2Factions",
    "trace": "projects/987816581230/traces/ABwppHH8PXibDZg8in1DjbP-caFy67Dtq025k_Uq2ofoPNXKtiPXrbJTmpGVUnVy-aY6H1MeZCFIpQ",
    "receiveTimestamp": "2019-03-08T19:01:10.388395945Z"
  }

帮助!

非常感谢任何有助于解决此问题的帮助或指导。让我知道您是否曾经遇到过这种情况、有潜在的解决方案或希望查看代码或日志的更多详细信息。非常感谢!

标签: node.jsgoogle-cloud-functionsdialogflow-esactions-on-google

解决方案


当我尝试修改我的一个谷歌助手应用程序时,我遇到了同样的错误。一切正常,但我突然遇到了和你一样的错误,我无法理解,与我的新开发无关。

{
 insertId:  "102mhl8g1omvh70"  
 labels: {
  channel:  "preview"   
  querystream:  "GOOGLE_USER"   
  source:  "JSON_RESPONSE_VALIDATION"   
 }
 logName:  "projects/myprojectID/logs/actions.googleapis.com%2Factions"  
 receiveTimestamp:  "2019-04-22T16:56:11.508733115Z"  
 resource: {
  labels: {
   action_id:  "actions.intent.MAIN"    
   project_id:  "myprojectID"    
   version_id:  ""    
  }
  type:  "assistant_action"   
 }
 severity:  "ERROR"  
 textPayload:  "MalformedResponse: Webhook error (206)"  
 timestamp:  "2019-04-22T16:56:11.498787357Z"  
 trace:  "projects/168413137357/traces/ABwppHG8ckJJgXMT5Jedih2WUtGNZZc9i0BVG5S-CkxCT8mkhy7mDr8L9GPd9p_EvXIIlTz3SK2z16jBK8Id"  
}

我试图通过禁用 webhook 并在对话流意图中设置播放负载来解决它。无论如何,我仍然收到此错误。

所以我试图通过上传旧版本的增量意图来回滚我的开发,但这没有用,我仍然得到我的错误观看我的函数日志我看到了这个

SyntaxError: Unexpected token : in JSON at position 6
at Object.parse (native)
at new User (/user_code/node_modules/actions-on-google/dist/service/actionssdk/conversation/user.js:75:43)
at DialogflowConversation.Conversation (/user_code/node_modules/actions-on-google/dist/service/actionssdk/conversation/conversation.js:47:21)
at DialogflowConversation (/user_code/node_modules/actions-on-google/dist/service/dialogflow/conv.js:36:9)
at WebhookClient.conv (/user_code/node_modules/dialogflow-fulfillment/src/dialogflow-fulfillment.js:415:14)
at welcome (/user_code/index.js:37:26)
at WebhookClient.handleRequest (/user_code/node_modules/dialogflow-fulfillment/src/dialogflow-fulfillment.js:273:44)
at exports.dialogflowFirebaseFulfillment.functions.https.onRequest (/user_code/index.js:247:11)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/providers/https.js:37:41)
at /var/tmp/worker/worker.js:783:7

我不明白助手的 json 是如何无法正确解析的,我感到非常惊讶。我比较了错误前后得到的 JSON 输入,发现用户存储条目的格式不正确。

我得到了类似的东西:

"user":{"userStorage":"\"data\":}","lastSeen":"2019-04-22T16:22:10Z","locale":"Mylanguage","userId":"ABwppHGoZFMQwTpdqZaOYBaIh32-hXH2kUN_EPJglUXMl5MeH7QlLyB9O0bCgZ0SQ9L0B2Ks-JQ9rHfRoAh-"}

而不是这个:

"user":{"userStorage":"{\"data\":{}}","lastSeen":"2019-04-21T17:55:21Z","locale":"Mylanguage","userId":"ABwppHGoZFMQwTpdqZaOYBaIh32-hXH2kUN_EPJglUXMl5MeH7QlLyB9O0bCgZ0SQ9L0B2Ks-JQ9rHfRoAh-"}

当您尝试从代理获取对话时,此 json 会引发错误,如下所示:

 let conv = agent.conv();

我仍然不明白这是怎么可能的,但我有一个技巧可以解决它。我通过在进行对话之前更正 json 来修复它。在我的应用程序中,我不需要任何用户存储,因此我总是在进行这样的对话之前正确初始化用户存储:

request.body.originalDetectIntentRequest.payload.user.userStorage = "{\"data\":{}}";

我即将联系对话流支持人员,通知他们我认为这是一个错误

我希望这个答案对你有所帮助!


推荐阅读