使用AWS Lex v2流与c++:签名不匹配



我正在尝试让我PC上的c++应用程序使用流api与AWS Lex v2通信。但是任何地方都没有示例代码,迫使我一直猜测流程。我设法把一些东西缝在一起,但不工作。我得到以下错误:

In Request handler:CRC不匹配。prelude_crc为0x0865223A22,但计算为0x08A98FE9C5响应处理程序:我们计算的请求签名与您提供的签名不匹配。检查您的AWS秘密访问密钥和签名方法。有关详细信息,请参阅服务文档。

秘密访问密钥没有任何问题,因为我能够从同一台PC从AWS CLI调用相同的bot,使用AWS lexv2-runtime recognition -text命令。

是否需要先用签名播种流?

AWS日志显示如下:

[ERROR] 2021 - 08 - 19 18:08 : 19.427 AWSClient[24956] HTTP response code : -1
Resolved remote host IP address :
Request ID :
Exception name :
Error message : Encountered network error when sending http request
0 response headers :
[WARN] 2021 - 08 - 19 18:08 : 19.427 AWSClient[24956] If the signature check failed.This could be because of a time skew.Attempting to adjust the signer.
[WARN] 2021 - 08 - 19 18:08 : 19.427 AWSClient[24956] Request failed, now waiting 50 ms before attempting again.
[WARN] 2021 - 08 - 19 18:08 : 19.489 WinHttpSyncHttpClient[24956] Failed setting TCP keep - alive interval with error code : 12018
[WARN] 2021 - 08 - 19 18:08 : 19.717 AWSErrorMarshaller[24956] Encountered AWSError 'InvalidSignatureException' : The request signature we calculated does not match the signature you provided.Check your AWS Secret Access Key and signing method.Consult the service documentation for details.
[ERROR] 2021 - 08 - 19 18:08 : 19.717 AWSClient[24956] HTTP response code : 403

我的整个测试代码如下,我错过了什么?既然我可以确认密钥和秘密是正确的,那么如何确保它是正确签名的呢?BOT区域是us-east-1,但是我是从另一个区域发出请求的。这有关系吗?

#include <aws/core/Aws.h>
#include <aws/core/client/AsyncCallerContext.h>
#include <aws/core/utils/Outcome.h>
#include <aws/core/auth/AWSCredentialsProvider.h>
#include <aws/lexv2-runtime/LexRuntimeV2Client.h>
#include <aws/lexv2-runtime/model/AudioInputEvent.h>
#include <aws/lexv2-runtime/model/RecognizeUtteranceRequest.h>
#include <aws/lexv2-runtime/model/RecognizeUtteranceResult.h>
#include <aws/lexv2-runtime/model/StartConversationHandler.h>
#include <aws/lexv2-runtime/model/StartConversationRequest.h>
#include <aws/lexv2-runtime/model/StartConversationRequestEventStream.h>
#include <aws/lex/LexRuntimeServiceClient.h>
#include <aws/lex/LexRuntimeServiceRequest.h>
#include <aws/lex/model/PostContentRequest.h>
#include <aws/lex/model/PostContentResult.h>
#include <iterator>
#include <nlohmann_json.hpp>
#include <fstream>
#include <chrono>
using namespace Aws::LexRuntimeV2;
int SessionCount = 0;
int main(int argc, char* argv[])
{
if (argc != 3)
{
std::cout << "Usage: LexV2Test pcm_audio.raw bot_name_cred.json" << std::endl;
return -1;
}
// read json file and populate the fields
std::ifstream jsonFile(argv[1]);
if (!jsonFile)
{
std::cout << "Cannot open license file " << argv[1] << std::endl;
return -1;
}
nlohmann::json jsonObj = nlohmann::json::parse(std::istreambuf_iterator<char>(jsonFile), std::istreambuf_iterator<char>());
jsonFile.close();
std::string lexKey, lexSecret;
std::string botId, botAliasId, localeId, sessionId, regionId;
botId = jsonObj["bot_id"];
botAliasId = jsonObj["bot_alias_id"];
lexKey = jsonObj["lex_key"];
lexSecret = jsonObj["lex_secret"];
localeId = jsonObj["lex_locale"];
Aws::SDKOptions options;
options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Info;
Aws::InitAPI(options);
Aws::Client::ClientConfiguration config;
config.region = jsonObj["lex_region"];
auto lexClient = Aws::MakeUnique<LexRuntimeV2Client>("MyClient", Aws::Auth::AWSCredentials(lexKey.c_str(), lexSecret.c_str()), config);
Model::StartConversationRequest LexRequest;
Model::StartConversationHandler requestHandler;
requestHandler.SetTranscriptEventCallback([](const Model::TranscriptEvent& ev)
{
std::cout << ev.GetTranscript() << std::endl;
});
requestHandler.SetOnErrorCallback([](const Aws::Client::AWSError<LexRuntimeV2Errors>& error)
{
std::cout << "Request handler: " << error.GetMessage() << std::endl;
});

LexRequest.WithLocaleId(localeId).WithBotId(botId.c_str()).WithBotAliasId(botAliasId.c_str()).WithSessionId("Blah")
.WithConversationMode(Model::ConversationMode::AUDIO).WithEventStreamHandler(requestHandler);
Aws::Utils::Threading::Semaphore signaling(0 /*initialCount*/, 1 /*maxCount*/);
auto OnResponseCallback = [&signaling](const LexRuntimeV2Client*,const Model::StartConversationRequest&,
const Model::StartConversationOutcome& outcome, const std::shared_ptr<const Aws::Client::AsyncCallerContext>&) 
{ 
std::cout << "Response handler: " << outcome.GetError().GetMessage();
signaling.Release(); 
};
Model::StartConversationRequestEventStream* pStream = nullptr;
Aws::Utils::Threading::Semaphore starting(0 /*initialCount*/, 1 /*maxCount*/);
auto OnStreamReady = [&starting,&pStream](Model::StartConversationRequestEventStream& stream)
{
pStream = &stream;
pStream->SetSignatureSeed("blah");
starting.Release();
};
lexClient->StartConversationAsync(LexRequest, OnStreamReady, OnResponseCallback, nullptr);
starting.WaitOne();
std::ifstream audioFile(argv[2], std::ios_base::binary);
if (!audioFile)
{
std::cout << "Cannot open audio file " << argv[2] << std::endl;
return 0;
}
while (!audioFile.eof())
{
unsigned char buf[320 + 1];
audioFile.read((char*)buf, 320);
Aws::Utils::ByteBuffer bytes(buf, audioFile.gcount());
Model::AudioInputEvent input;
auto millisec_since_epoch = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock().now().time_since_epoch()).count();
input.SetClientTimestampMillis(millisec_since_epoch);
input.SetAudioChunk(bytes);
input.SetContentType("audio/lpcm; sample-rate=8000; sample-size-bits=16; channel-count=1; is-big-endian=false");
pStream->WriteAudioInputEvent(input);
_sleep(20);
}
signaling.WaitOne(); // prevent the application from exiting until we're done
Aws::ShutdownAPI(options);
return 0;
}

原来这是Windows上的WinHttp/WinINet的限制。它还不完全支持HTTP/2多路复用。所以我切换到CURL,它成功了。

Since AWSstreaming lex/transcript功能需要HTTP/2多路复用,总是使用CURL。

Aws::Client::ClientConfiguration config;
config.httpLibOverride = Aws::Http::TransferLibType::CURL_CLIENT;

最新更新