POST url 编码形式到 Amazon API 网关

POST url encoded form to Amazon API Gateway

我正在创建一个 webhook 来接收来自第三方服务的通知,他们在内容类型为 application/x-www-form-urlencoded.

的 POST 正文中发送了数据

但它产生了同样的错误:

{"message": "Could not parse request body into json: Unrecognized token \'name\': was expecting \'null\', \'true\', \'false\' or NaN\n at [Source: [B@456fe137; line: 1, column: 6]"}

我可以通过以下 curl 调用重现该错误:

% curl -v -X POST -d 'name=Ignacio&city=Tehuixtla' https://rl9b6lh8gk.execute-api.us-east-1.amazonaws.com/prod/mandrillListener
*   Trying 54.230.227.63...
* Connected to rl9b6lh8gk.execute-api.us-east-1.amazonaws.com (54.230.227.63) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate: *.execute-api.us-east-1.amazonaws.com
* Server certificate: Symantec Class 3 Secure Server CA - G4
* Server certificate: VeriSign Class 3 Public Primary Certification Authority - G5
> POST /prod/mandrillListener HTTP/1.1
> Host: rl9b6lh8gk.execute-api.us-east-1.amazonaws.com
> User-Agent: curl/7.43.0
> Accept: */*
> Content-Length: 27
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 27 out of 27 bytes
< HTTP/1.1 400 Bad Request
< Content-Type: application/json
< Content-Length: 180
< Connection: keep-alive
< Date: Thu, 28 Jan 2016 12:29:40 GMT
< x-amzn-RequestId: cd4d9232-c5ba-11e5-a158-b9b39f0b0599
< X-Cache: Error from cloudfront
< Via: 1.1 1915b8b49d2fbff532431a79650103eb.cloudfront.net (CloudFront)
< X-Amz-Cf-Id: cxU2_b5DzIw4M_n3hJBFXTu9AVRBL3GpbQqUId9IxgS004DfLYqYmg==
<
* Connection #0 to host rl9b6lh8gk.execute-api.us-east-1.amazonaws.com left intact
{"message": "Could not parse request body into json: Unrecognized token \'name\': was expecting \'null\', \'true\', \'false\' or NaN\n at [Source: [B@d92973b; line: 1, column: 6]"}

如果我用双引号将正文括起来,它就可以正常工作:

% curl -v -X POST -d '"name=Ignacio&city=Tehuixtla"' https://rl9b6lh8gk.execute-api.us-east-1.amazonaws.com/prod/mandrillListener
*   Trying 54.230.227.19...
* Connected to rl9b6lh8gk.execute-api.us-east-1.amazonaws.com (54.230.227.19) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate: *.execute-api.us-east-1.amazonaws.com
* Server certificate: Symantec Class 3 Secure Server CA - G4
* Server certificate: VeriSign Class 3 Public Primary Certification Authority - G5
> POST /prod/mandrillListener HTTP/1.1
> Host: rl9b6lh8gk.execute-api.us-east-1.amazonaws.com
> User-Agent: curl/7.43.0
> Accept: */*
> Content-Length: 29
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 29 out of 29 bytes
< HTTP/1.1 200 OK
< Content-Type: application/json
< Content-Length: 6
< Connection: keep-alive
< Date: Thu, 28 Jan 2016 12:33:20 GMT
< x-amzn-RequestId: 50610606-c5bb-11e5-b140-5d837ffe26ed
< X-Cache: Miss from cloudfront
< Via: 1.1 a670cda0e28541e40881b95b60c672b7.cloudfront.net (CloudFront)
< X-Amz-Cf-Id: mCLKL4eOnpUMd15IXQZw0RStJHw9Vdf3ivdCl37dcmno2JFOfxw0Vg==
<
* Connection #0 to host rl9b6lh8gk.execute-api.us-east-1.amazonaws.com left intact
"true"%

兰巴只有一行:

context.succeed('true');

如何使 api 网关不将正文视为 json?

我尝试了有关模板映射的文档,但没有成功,我什至尝试将其转换为静态模板,根本没有变量!在所有情况下,错误都发生在进入我的代码之前。

尝试设置映射模板如下:

{
  "body" : $input.json('$')
}

这会将您的字符串转换为 json 并传递给 lambda。

来自亚马逊docs$input.json(x) 函数计算 JSON 路径表达式,returns 结果作为 JSON 字符串。

使表单数据正常工作的映射模板非常复杂。这是一个要点:https://gist.github.com/ryanray/668022ad2432e38493df

另外,你可以看到我写的这个 post 有一个如何与 Slack 集成的例子(他们的钩子将 POST 作为表单数据发送到 API 网关): http://www.ryanray.me/serverless-slack-integrations

这并不完全相关,但如果您是 Amazon API Gateway 的新手,我不知道还需要一个额外的步骤是(重新)部署您的 API 在按照其他人的建议添加映射模板后(在您之前部署了 API 的情况下)。这花费了我大量的调试时间,因为我不明白为什么即使在提出此处发布的建议后我仍然继续收到此错误。

如果使用 AWS 控制台,

  • 导航到 API
  • 中的任何窗格
  • Select 顶部的操作菜单
  • Select 从菜单中部署 API,选择相关阶段并确认

API 网关 中,select POST 方法为您的资源,select 集成请求并为application/x-www-form-urlencoded:

创建一个新的映射模板
#set($body = $input.path('$'))
#set($jsonString = $util.urlencode($body))
#set($json = $util.parsejson($jsonString))

{
  "body" : $json,
}

或者,您可以简单地传递 url 编码的字符串:

#set($body = $input.path('$'))
{
  "body" : "$body",
}

和 url 解码并解析 lambda 中的 JSON。