当前位置: 首页 > 知识库问答 >
问题:

AWS HTTP API-Python请求与Dart HTTP中的请求相同,但响应不同

路和悌
2023-03-14

我试图在Flutter应用程序中使用AWS DynamoDB,由于缺乏官方的AWS Dart SDK,我被迫使用低级别的HTTP REST API。

签署AWS HTTP请求的方法非常繁琐,但使用AWS提供的示例作为指导,我能够相对轻松地将Python转换为Dart。最终结果是两组代码产生相同的身份验证签名。

当我真的去发送请求时,我的问题来了。Python的工作原理与预期一致,但使用Dart的HTTP包发送POST会导致错误

我们计算的请求签名与您提供的签名不匹配。检查您的AWS秘密访问密钥和签名方法。详情请咨询服务留档。

我将为您提供生成auth签名的实际代码,因为只需发送相同的硬编码请求,就可以复制该问题。请参见下面的Python和Dart代码。

注意:一个有效的响应将返回

签名过期:20190307T214900Z现在比20190307T215809Z早(20190307T221309Z-15分钟)

由于请求签名使用当前日期,因此仅在15分钟内有效。

*****PYTHON代码*****

import requests

headers = {'Content-Type':'application/json',
           'X-Amz-Date':'20190307T214900Z',
           'X-Amz-Target':'DynamoDB_20120810.GetItem',
           'Authorization':'AWS4-HMAC-SHA256 Credential=AKIAJFZWA7QQAQT474EQ/20190307/ap-southeast-2/dynamodb/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-target, Signature=297c5a03c59db6da45bfe2fda6017f89a0a1b2ab6da2bb6e0d838ca40be84320'}

endpoint = 'https://dynamodb.ap-southeast-2.amazonaws.com/'
request_parameters =  '{"TableName": "player-exports","Key": {"exportId": {"S": "HG1T"}}}'

r = requests.post(endpoint, data=request_parameters, headers=headers)

print('Response status: %d\n' % r.status_code)
print('Response body: %s\n' % r.text)

飞镖代码

import 'package:http/http.dart' as http;

void main(List<String> arguments) async {

  var headers = {'Content-Type':'application/json',
           'X-Amz-Date':'20190307T214900Z',
           'X-Amz-Target':'DynamoDB_20120810.GetItem',
           'Authorization':'AWS4-HMAC-SHA256 Credential=AKIAJFZWA7QQAQT474EQ/20190307/ap-southeast-2/dynamodb/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-target, Signature=297c5a03c59db6da45bfe2fda6017f89a0a1b2ab6da2bb6e0d838ca40be84320'};

  var endpoint = 'https://dynamodb.ap-southeast-2.amazonaws.com/';
  var request_parameters =  '{"TableName": "player-exports","Key": {"exportId": {"S": "HG1T"}}}';

  http.post(endpoint, body: request_parameters, headers: headers).then((response) {
    print("Response status: ${response.statusCode}");
    print("Response body: ${response.body}");
  });
}

endpoint、标头和正文实际上是在两组代码之间复制和粘贴的。

Dart HTTP的工作原理是否有一些细微差别,我在这里没有提到?是否发生了头或请求参数的map/string/json转换?

我注意到的一件事是,在AWS提供的示例中,它指出

对于DynamoDB,请求可以包括任何头,但必须包括“主机”、“x-amz-date”、“x-amz-target”、“内容类型”和“授权”。除授权标头外,标头必须包含在规范的\u标头和签名的\u标头值中,如前所述。这里的秩序并不重要。Python注:“主机”头由Python“请求”库自动添加。

但是

a) 当我在Dart代码的头中添加'Host':'dynamodb.ap-southest-2.amazonaws.com'时,我得到了相同的结果

b) 如果在Python请求返回后查看r.request.headers,我可以看到它自动添加了一些新的头(内容长度等),但“Host”不是其中之一。

你知道为什么看起来相同的HTTP请求适用于Python请求而不适用于Dart HTTP吗?

共有1个答案

白禄
2023-03-14

好了,现在问题解决了。我的问题在某种程度上是一个巨大的用户错误。我正在使用一个新的IDE,当我生成我提供的硬编码示例时,我实际上仍在执行前一个文件。愚蠢,愚蠢,愚蠢。

但是

我能够理清导致我首先提出这个问题的实际问题。我发现,如果在标题中将内容类型设置为“application/json”,dart HTTP包会自动附加“charset=utf-8”。因为该值是auth签名的一部分,所以当AWS对来自报头的值进行编码以与用户生成的签名进行比较时,它们不匹配。

修复方法只是为了确保在设置标题内容类型时,确保手动将其设置为“application/json;charset=utf-8”,而不是“application/json”。

在这里发现了更多关于这个“错误”的讨论。

 类似资料:
  • 网络爬虫工作过程可以理解为模拟浏览器操作的过程,浏览器的主要功能是向服务器发出请求,在浏览器窗口中展示服务器返回的网络资源。 一、浏览器处理网页的过程 我们先来看一下浏览网页的基本过程,比如我们在浏览器地址栏输入:http://www.baidu.com 回车后会浏览器会显示百度的首页。 这段网络通信过程中到底发生了什么?简单来说这段过程发生了以下四个步骤: 当我们在浏览器输入URL http:/

  • 在SpringMVC项目中,客户机发送一个带有序列化对象的请求,客户机本身是一个小程序,所以它不希望收到一个web页面作为响应,而是一个带有字符串对象的响应,该响应将告诉他这是成功还是失败。那么解决方案是什么呢?我想在@Controller中使用返回void的方法,或者返回不存在页面的方法?(在这两种情况下,我还想知道是否有回复给客户)

  • 介绍 YurunHttp 的请求响应类,结果类。除了遵循 PSR-7 规范,另外还增加了一些人性化的方法。 类:Yurun\Util\YurunHttp\Http\Response use Yurun\Util\HttpRequest; $http = new HttpRequest; $response = $http->get('http://www.baidu.com'); 方法 响应内

  • 问题内容: 我正在尝试通过COM端口发送AT命令,但只重新发送了相同的命令。 日志: 16:19:21.910 [main]调试SerialConnections.M234Serial-创建实例。 16:19:21.974 [main]调试SerialConnections.M234Serial-发送请求:AT ^ SCFG? 16:19:23.976 [EventThread COM55]调试S

  • 是否可以在不等待响应的情况下发送HTTP请求? 我在做一个物联网项目,需要记录传感器的数据。在每一个设置中,都有许多传感器,一个中央协调器(主要由Raspberry Pi实现)从传感器收集数据,并通过Internet将数据发送到服务器。 提前感谢! 编辑:传感器是无线的,但他们使用的技术在发送到协调器时很少(或没有)延迟。此协调器必须通过Internet发送数据。但是,假设互联网连接不好。因为这将