简体   繁体   English

cMalformedResponse:Webhook错误(206)同时看似有效的Webhook响应-Node.js中对Google Dialogflow应用的操作

[英]cMalformedResponse: Webhook error (206) whilst a seemingly valid webhook response - Actions on Google Dialogflow app in Node.js

Problem 问题

I am developing a Actions on Google app (intended for the Google Home), using the Actions on Google library for Node.js, hosted on Firebase Google Functions, via Dialogflow. 我正在通过Dialogflow使用Firebase Google Functions上托管的Node.js在Google上的库中开发Google上的Actions应用程序(打算用于Google Home)。 I often, but irregularly (and hard to replicate), encounter an error, forcing the Actions on Google (simulator or Google Home itself) to shut down my app. 我经常但不定期地(且难以复制)遇到错误,迫使Google上的操作(模拟器或Google Home本身)关闭我的应用程序。 I route everything from any Dialogflow intent (including fallbacks) to my webhook fulfilment, and - based on the log files - the webhook responds quickly (within ~200ms) and with valid responses (investigating the JSON responses). 我将所有Dialogflow意图(包括回退)路由到我的Webhook实现中,并且-基于日志文件-Webhook快速响应(约200毫秒内)并且具有有效响应(调查JSON响应)。 However, the Actions on Google seems to reject the response and triggers the Dialogflow default text response. 但是,Google上的操作似乎拒绝了响应,并触发了Dialogflow默认文本响应。 My biggest concern, is that it happens at different stages in the conversation, sometimes already at the Welcome event. 我最大的担心是,它发生在对话的不同阶段,有时已经出现在“欢迎”事件中。 It is also noticeable that - even though the fulfillment responds in milliseconds (~200), the Actions on Google / Dialogflow takes its time and - what I believe - has a timeout. 同样值得注意的是-即使完成响应以毫秒为单位(〜200),Google / Dialogflow上的操作仍会花费时间,而且-我相信-会超时。 Below are my explorations into the potential cause. 以下是我对潜在原因的探索。 But frankly, I am out of ideas. 但坦率地说,我没有主意。

-- Edit -- -编辑-

The service seems to run better now - I haven't experience this error. 该服务现在似乎运行得更好-我没有遇到此错误。 I have changed the code to call admin.firestore() less often, by using a global databse and passing it through. 我已经更改了代码,以通过使用全局数据库并将其传递通过,从而减少了对admin.firestore()的调用。 I had a hunch that, potentially the https functions were called simultaneously which might have caused a malformed response somehow. 我有一种预感,可能同时调用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);
 });
}

I also found a flaw in my intent handeling, which caused no intent to be matched. 我还发现我的意图处理存在缺陷,导致没有意图被匹配。 I've restructured the Dialogflow intents to have less possibility of this no-intent (I basically made a two-step question to determine the user's intention). 我已经对Dialogflow意图进行了重组,以减少这种无意图的可能性(我基本上提出了一个两步式问题来确定用户的意图)。 However, since the webhook did response correctly, I don't believe this was the problem. 但是,由于Webhook确实能够正确响应,所以我不认为这是问题所在。 Still, I find it an odd error - so if anyone has more pointers please! 不过,我发现它是一个奇怪的错误-因此,如果有人有更多的指针,请!

-- end edit -- - 结束编辑 -

Logs 日志

This is a response from the webhook as seen from the Google Functions Log - indicating a send response to the Dialogflow app. 这是来自Webhook的响应,从Google Functions日志中可以看到-表示已将响应发送到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}"
        }
      }
    ]
  }
}

However, this is what the Actions on Google console shows. 但是,这就是在Google控制台上显示的操作。 The textToSpeech response is the default text response where DialogFlow can fall back to in case the fulfilment fails (as suggested by https://medium.com/google-developers/debugging-common-actions-on-google-errors-7c8527378d27 ) 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"
    }
  }
}

The stackdriver logs also indicate the latter case, where the default response from Dialogflow is received. 堆栈驱动程序日志还指示后一种情况,即从Dialogflow接收默认响应。

Thoughts 思考

I have tried to replicate this error on the simulator, on my phone and on a Google Home. 我试图在模拟器,手机和Google Home上复制此错误。 It occurs at different moments, though seems to occur more frequently than before. 尽管似乎比以前更频繁地发生,但它发生在不同的时刻。 My three hunches are the following: 我的三个预感如下:

  1. Overload. 超载。 My Google Functions hosts 8 functions, including the Dialogflow app. 我的Google Functions托管8个功能,包括Dialogflow应用程序。 Perhaps if the other functions are also called frequently at a given moment, something goes wrong with the Dialogflow app handeling the https requests from Dialogflow (the Google Assistant). 也许如果在给定时刻也频繁调用其他功能,则Dialogflow应用程序处理来自Dialogflow(Google助手)的https请求会出问题。 However, I do not see how this should happen. 但是,我不知道这应该如何发生。 I could replicate (sometimes) the problem by invoking the app on two devices with two different accounts. 通过在具有两个不同帐户的两个设备上调用应用程序,我可以复制(有时)问题。 But since it also happens with one account I don't see this can be the only problem. 但是由于一个帐户也会发生这种情况,因此我认为这不是唯一的问题。 I've followed this tip to reduce overload ( https://stackoverflow.com/a/47985480/7053198 ) but that did not seem to help my issue. 我遵循了这个技巧来减少过载( https://stackoverflow.com/a/47985480/7053198 ),但这似乎对我的问题没有帮助。 Can then the upscaling of Google Functions be a problem here? Google职能升级是否可能成为问题所在?
  2. Promise hell. 答应地狱。 I am using a number of promises (or more callbacks) to communicate with a Firestore database to retreive user data. 我正在使用许多Promise(或更多回调)与Firestore数据库进行通信以检索用户数据。 However, I can invoke these intents quite rapidly, and they resolve nicely - up to a point where they don't. 但是,我可以很快地调用这些意图,并且它们可以很好地解决-直到它们无法解决为止。 Below is a snippet of such one intent. 以下是这种意图的摘要。
  3. Size of my app . 我的应用程式大小 The number of Intents has gotten quite large, and there is a lot of communication between the Google Functions and the Firestore database. Intent的数量已经非常多,并且Google Functions和Firestore数据库之间的通信很多。 I just don't know how this might influence the rejection of the seemingly correct response by Dialogflow. 我只是不知道这将如何影响Dialogflow拒绝看似正确的响应。

Intent with promises snippet: 带有承诺代码段的意图:

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;
  });
});

Problem Example Log 问题示例日志

For good measure, here three log entries from the stackdriver side of things: 出于良好的考虑,这里是堆栈驱动程序方面的三个日志条目:

{
    "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"
  }

Help! 救命!

Any help or guidance towards unraveling this issue is much apreciated. 对于解决此问题的任何帮助或指导都非常感谢。 Let me know if you have experienced this before, have a potential solution or would like to see more details of the code or logs. 让我知道您是否曾经有过此经历,是否有潜在的解决方案,或者想查看代码或日志的更多详细信息。 Many thanks! 非常感谢!

I got the same error when I tried to modify one of my google assistant app. 当我尝试修改我的Google助手应用程序之一时,出现了相同的错误。 Everything was working well but I suddently got the same error as you that I was not able to understand and was not related to my new developpement. 一切工作正常,但我突然遇到了与您相同的错误,我无法理解,并且与我的新发展无关。

{
 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"  
}

I tried to solve it by disabling the webhook and set the playload in the dialogflow intent. 我试图通过禁用Webhook并在dialogflow目的中设置播放负载来解决该问题。 Anyway I still got this error. 无论如何,我仍然遇到此错误。

So I tried to rollback on my developpement by uploading the old version the incremeneted intent but this didn't work and I still got my error Watching to my function logs I saw this 因此,我尝试通过上传旧版本具有极好的意图来回滚我的开发,但这没有用,并且仍然出现错误。看着我的功能日志,我看到了

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

I didn't understand how the json from the assistant could not be parsed properly I was very surprised. 我不明白如何无法正确解析助手的json,我感到非常惊讶。 I compared the JSON input that I got before and after the bug and I saw that the userstorage entry was not well formated. 我比较了错误前后的JSON输入,发现userstorage条目的格式不正确。

I got something like that : 我得到这样的东西:

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

instead of this : 代替这个:

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

And this json is going to provoke an error when you try to get the conversation from the agent such like that : 当您尝试从代理获取对话时,例如,该json将引发错误:

 let conv = agent.conv();

I still don't understand how this is even possible but I have a trick to solve it. 我仍然不知道这怎么可能,但是我有解决的办法。 I fix it by correcting the json before getting the conversation. 我通过在对话之前更正json来解决它。 In my app I don't need any userstorage so I always intialise the userstorage properly before getting the conversation like that : 在我的应用中,我不需要任何用户存储,因此在进行这样的对话之前,我总是正确地初始化用户存储:

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

I am about to contact the dialogflow support to inform them of this I consider to be a bug 我将与dialogflow支持人员联系,以告知他们这一情况,我认为这是一个错误

I hope this answer is helping you! 希望这个答案对您有所帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM