我在使用 AWS Kinesis 时遇到了一些问题,因为我设置了一个流,并且我想使用标准 http POST
请求在我的流上调用 Kinesis PutRecord 调用。我这样做是因为生成的 javascript 应用程序的包大小很重要,而且我宁愿不导入 aws-sdk
来完成应该(在纸面上)可能的事情。
请注意,我查看过 this other stack overflow question about the same thing这是......有点信息性的。
现在,我已经有了一种使用访问 key 、 secret token 和 session token 对请求进行 sigv4 签名的方法。但是当我最终得到签署请求的结果并使用浏览器内的 fetch
api 发送它时,服务会使用(或使用引用相同内容的 json 对象,具体取决于我的 Content-Type标题,我猜)作为结果。
这是我正在使用的代码
// There is a global function "sign" that does sigv4 signing
// ...
var payload = {
Data: { task: "Get something working in kinesis" },
PartitionKey: "1",
StreamName: "MyKinesisStream"
}
var credentials = {
"accessKeyId": "<access.key>",
"secretAccessKey": "<secret.key>",
"sessionToken": "<session.token>",
"expiration": 1528922673000
}
function signer({ url, method, data }) {
// Wrapping with URL for piecemeal picking of parsed pieces
const parsed = new URL(url);
const [ service, region ] = parsed.host.split(".");
const signed = sign({
method,
service,
region,
url,
// Hardcoded
headers : {
Host : parsed.host,
"Content-Type" : "application/json; charset=UTF-8",
"X-Amz-Target" : "Kinesis_20131202.PutRecord"
},
body : JSON.stringify(data),
}, credentials);
return signed;
}
// Specify method, url, data body
var signed = signer({
method: "POST",
url: "https://kinesis.us-west-2.amazonaws.com",
data : JSON.stringify(payload)
});
var request = fetch(signed.url, signed);
当我查看请求的结果时,我得到:
{
Output: {
__type: "com.amazon.coral.service#InternalFailure"},
Version: "1.0"
}
现在我不确定 Kinesis 是否真的在这里失败了,或者我的输入是否格式错误?
这是签名请求的样子
{
"method": "POST",
"service": "kinesis",
"region": "us-west-2",
"url": "https://kinesis.us-west-2.amazonaws.com",
"headers": {
"Host": "kinesis.us-west-2.amazonaws.com",
"Content-Type": "application/json; charset=UTF-8",
"X-Amz-Target": "Kinesis_20131202.PutRecord",
"X-Amz-Date": "20180613T203123Z",
"X-Amz-Security-Token": "<session.token>",
"Authorization": "AWS4-HMAC-SHA256 Credential=<access.key>/20180613/us-west-2/kinesis/aws4_request, SignedHeaders=content-type;host;x-amz-target, Signature=ba20abb21763e5c8e913527c95a0c7efba590cf5ff1df3b770d4d9b945a10481"
},
"body": "\"{\\\"Data\\\":{\\\"task\\\":\\\"Get something working in kinesis\\\"},\\\"PartitionKey\\\":\\\"1\\\",\\\"StreamName\\\":\\\"MyKinesisStream\\\"}\"",
"test": {
"canonical": "POST\n/\n\ncontent-type:application/json; charset=UTF-8\nhost:kinesis.us-west-2.amazonaws.com\nx-amz-target:Kinesis_20131202.PutRecord\n\ncontent-type;host;x-amz-target\n508d2454044bffc25250f554c7b4c8f2e0c87c2d194676c8787867662633652a",
"sts": "AWS4-HMAC-SHA256\n20180613T203123Z\n20180613/us-west-2/kinesis/aws4_request\n46a252f4eef52991c4a0903ab63bca86ec1aba09d4275dd8f5eb6fcc8d761211",
"auth": "AWS4-HMAC-SHA256 Credential=<access.key>/20180613/us-west-2/kinesis/aws4_request, SignedHeaders=content-type;host;x-amz-target, Signature=ba20abb21763e5c8e913527c95a0c7efba590cf5ff1df3b770d4d9b945a10481"
}
(测试 key 由生成签名的库使用,因此请忽略它) (此外,正文中可能有额外的斜杠,因为我使用 JSON.stringify 漂亮地打印了响应对象)。
我的问题:我遗漏了什么吗? Kinesis 是否需要 header a、b 和 c,而我只生成其中两个?或者这个内部错误是一个实际的故障吗?我迷失了,因为回复表明我无能为力。
感谢任何帮助!
编辑:作为第二个问题,我是否正确使用了 X-Amz-Target
header ?只要您访问该服务端点,这就是您调用服务函数的方式,不是吗?
更新:按照迈克尔的评论,我已经取得了一些进展,但我仍然没有解决问题。这是我所做的:
我确保在我的 payload
中,我仅在 Data
属性上运行 JSON.stringify
。
我还将 Content-Type
header 修改为 "Content-Type": "application/x-amz-json-1.1"
因此,我'我收到了稍微更有用的错误消息。
现在,我的有效负载仍然基本相同:
var payload = {
Data: JSON.stringify({ task: "Get something working in kinesis" }),
PartitionKey: "1",
StreamName: "MyKinesisStream"
}
我的签名者函数体如下所示:
function signer({ url, method, data }) {
// Wrapping with URL for piecemeal picking of parsed pieces
const parsed = new URL(url);
const [ service, region ] = parsed.host.split(".");
const signed = sign({
method,
service,
region,
url,
// Hardcoded
headers : {
Host : parsed.host,
"Content-Type" : "application/json; charset=UTF-8",
"X-Amz-Target" : "Kinesis_20131202.PutRecord"
},
body : data,
}, credentials);
return signed;
}
因此,我传入一个部分序列化的对象(至少数据是),当我将其发送到服务时,我得到的响应是:
{"__type":"SerializationException"}
这至少有一点帮助,因为它告诉我我的输入在技术上是不正确的。不过,我做了一些事情来尝试纠正这个问题:
- 我已在整个负载上运行
JSON.stringify
- 我已将
Data
键更改为字符串值,以查看它是否会通过 - 我尝试在数据上运行
JSON.stringify
,然后运行 btoa
,因为我读到了另一篇对某人有用的帖子。
但我仍然遇到同样的错误。我感觉我已经如此接近了。你能发现我可能遗漏的东西或者我没有尝试过的东西吗?我遇到了零星的未知操作异常,但我认为现在这个序列化让我难住了。
编辑2:
事实证明,Kinesis 只接受 base64
编码的字符串。这可能是 aws-sdk 提供的一个优点,但本质上它所需要的只是 Data: btoa(JSON.stringify({ task: "data"}))
中的让它工作的有效负载
最佳答案
虽然我不确定这是唯一的问题,但您似乎正在发送一个包含错误序列化(双编码)有效负载的请求正文。
var obj = { foo: 'bar'};
JSON.stringify(obj) 返回一个字符串...
'{"foo": "bar"}' // the ' are not part of the string, I'm using them to illustrate that this is a thing of type string.
...当使用 JSON 解析器进行解析时,它返回一个对象。
{ foo: 'bar' }
但是,JSON.stringify(JSON.stringify(obj)) 返回不同的字符串...
'"{\"foo\": \"bar\"}"'
...但是解析时,返回一个字符串。
'{"foo": "bar"}'
服务端点期望解析主体并获取一个对象,而不是字符串...因此,解析请求主体(从服务的角度)不会返回正确的类型。该错误似乎是服务无法在非常低的级别解析您的请求。
在您的代码中,body: JSON.stringify(data)
应该只是 body: data
因为之前您已经使用 data 创建了一个 JSON 对象: JSON.stringify(有效负载)
.
正如所写,您实际上将 body
设置为 JSON.stringify(JSON.stringify(payload))。
关于amazon-web-services - 理论上是否可以通过单个 http POST 请求在 Kinesis 中使用 `putRecord`?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50847879/