Я пытаюсь использовать AWS DynamoDB в приложении Flutter, и из-за отсутствия официального пакета AWS SDK для Dart я вынужден использовать низкоуровневый HTTP REST API.
Метод подписания AWSHTTP-запрос довольно утомителен, но, используя предоставленный AWS пример в качестве руководства, я смог довольно легко преобразовать Python в Dart строка за строкой.Конечным результатом были оба набора кода, производящие одинаковые подписи аутентификации.
Моя проблема возникла, когда я фактически отправил запрос.Python работает как положено, но отправка POST с HTTP-пакетом Dart выдает ошибку
Рассчитанная нами подпись запроса не соответствует предоставленной вами подписи.Проверьте свой секретный ключ доступа AWS и метод подписи.За подробностями обращайтесь к документации по сервису.
Я избавлю вас от фактического кода для генерации подписи аутентификации, поскольку проблема может быть воспроизведена простым отправлением того же запроса в жестком коде.См. Код Python и Dart ниже.
Примечание: верный ответ вернет
Срок действия подписи истек: 20190307T214900Z более ранний, чем 20190307T215809Z (20190307T221309Z - 15 мин.)
, поскольку подпись запроса использует текущую дату и действительна только в течение 15 минут.
***** КОД ПИТОНА *****
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)
***** DART CODE *****
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}");
});
}
Конечная точка, заголовки и тело буквально копируются и вставляются между двумя наборами кода.
Есть ли какой-то нюанс в том, как Dart HTTPработает, что мне здесь не хватает?Есть ли какое-либо преобразование заголовков или request_paramaters для map / string / json?
Одна вещь, которую я заметил, состоит в том, что в приведенном примере AWS говорится:
Для DynamoDB запросможет включать любые заголовки, но ДОЛЖЕН включать «host», «x-amz-date», «x-amz-target», «content-type» и «Authorization».За исключением заголовка авторизации, заголовки должны быть включены в значения canonical_headers и signature_headers, как отмечалось ранее.Порядок здесь не имеет значения.Примечание к Python: заголовок 'host' автоматически добавляется библиотекой Python 'запросы'.
Но
a) Когда я добавляю 'Host': 'dynamodb.ap-southeast-2.amazonaws.com 'к заголовкам в коде Dart, я получаю тот же результат
и
б) Если я посмотрю на r.request.headers после возврата запросов Python, явидно, что он добавил несколько новых заголовков (Content-Length и т. д.) автоматически, но «Host» не является одним из них.
Любые идеи, почему на первый взгляд такой же HTTP-запрос работает для запросов Python, но не для DartHTTP