потоковая передача ответа от Lambda с помощью InvokeWithResponseStreamCommand
У меня есть следующий код в приложении, реагирующем на реакцию, которое вызывает Lambda в моем клиенте AWS. Lambda срабатывает нормально, все журналы console.log отображаются правильно (200, правильный тип контента и т. д.), и я также вижу ответ от Lambda в CloudWatch, и это ожидаемый результат (потоковый ответ). . У меня также есть этот код, работающий в обычном React, и он тоже работает нормально, и я получаю ожидаемый результат.
Однако в React-Native ответ приходит по-другому и вызывает исключение, которое я не смог выяснить. Судя по этой документации AWS , в EventStream должно быть что-то (InvokeComplete, PayloadChunk), но судя по логам, я, похоже, ничего не получаю.
import { Lambda, InvokeWithResponseStreamCommand, LambdaClient } from "@aws-sdk/client-lambda"
import "react-native-url-polyfill/auto";
import 'react-native-get-random-values'
async streamAWS(payload) {
try {
const lambda = new Lambda({
region: 'us-west-1',
credentials: {
accessKeyId,
secretAccessKey
}
});
return lambda.send(new InvokeWithResponseStreamCommand(
{
FunctionName: 'test_stream',
Payload: JSON.stringify({ payload })
}
));
} catch (error) {
console.log(error);
}
}
Это код, который я использую для извлечения потоковых данных. Как я уже сказал, этот код отлично работает в React Web, но не работает в React-Native:
import { TextDecoder } from 'text-decoding';
useLayoutEffect(() => {
async function stream() {
const lambdaResponse = await awsService("payload");
const decoder = new TextDecoder("utf-8");
console.log(JSON.stringify(lambdaResponse));
// this for causes the exception on React-Native
for await (const event of lambdaResponse.EventStream) {
const text = decoder.decode(event.PayloadChunk?.Payload);
setTitle(oldText => oldText + text.replaceAll('"', ''));
}
}
stream();
}, []);
Это ошибка, которую я получаю в React-Native:
LOG response:
{"$metadata":{"httpStatusCode":200,"requestId":"b8eee2d1-a8e2-404f-9df3-dccb4810fdcd","attempts":1,"totalRetryDelay":0},"ExecutedVersion":"$LATEST","ResponseStreamContentType":"application/vnd.amazon.eventstream","EventStream":{},"StatusCode":200}
WARN Possible Unhandled Promise Rejection (id: 0):
TypeError: Object is not async iterable TypeError: Object is not async iterable
И я использую эту библиотеку и версию: "@aws-sdk/client-lambda": "3.335.0"
РЕДАКТИРОВАТЬ: Я также думаю, что основная проблема заключается в том, что свойство EventStream лямбда-ответа возвращается пустым , когда я вызываю его из собственного реагирования (вы можете увидеть это в разделе журнала EventStream:{}).
1 ответ
Кажется, чтоawait for ... of
синтаксис не поддерживается в React Native. Самое простое решение — предоставить собственную функцию итератора. К счастью, спецификация итератора довольно проста; звонюnext
возвращает объект с двумя свойствами{ value, done }
.value
неудивительно, что это ваша следующая ценность.done
— логическое значение, указывающее, завершился ли итератор, возвращая дополнительные значения.
Приведенная ниже функция возьмет итератор, соберет его значения и вернет их в виде массива.
async function IteratorToArray(iterator) {
const items = [];
while (true) {
const { value, done } = await iterator.next();
if (done) {
return items; // 'value' will be undefined on last iteration as it was 'done'
} else {
items.push(value);
}
}
}
Итак, для вашей проблемы вы можете назвать ее так:
const lambdaResponse = await awsService("payload");
const data = await IteratorToArray(lambdaResponse.EventStream);
const decoder = new TextDecoder("utf-8");
for (const event of data) {
const text = decoder.decode(event.PayloadChunk?.Payload);
setTitle(oldText => oldText + text.replaceAll('"', ''));
}