amazon-web-services - 理论上是否可以通过单个 http POST 请求在 Kinesis 中使用 `putRecord`?

标签 amazon-web-services aws-sdk amazon-kinesis

我在使用 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/

相关文章:

php - aws s3 sdk php 在 getObjects 时遇到永久重定向

node.js - MoonMail 安装问题 - 资源部署期间出错

java - 即使在 Eclipse 中执行 Maven 更新后也无法导入依赖项

asp.net - 使用elastic beanstalk部署Asp.net Web应用程序问题

go - 如何在 golang (aws sdk-for-go) 中正确地将 map 解压到自定义嵌套结构中

apache-spark - Spark Streaming forEachBatch 在写入数据库时​​给出不一致/无序的结果

amazon-web-services - 是否可以从 AWS 外部访问 Amazon Kinesis

amazon-kinesis - 启动 Kinesis 消费者应用程序时如何使用 DynamoDB 表的状态?

c# - 推送到 SQS 时的 AWS SNS 元数据

javascript - 页面加载太慢 Jquery 和外部亚马逊图片文件