coreHTTP 双向身份验证演示 - FreeRTOS
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

coreHTTP 双向身份验证演示

Introduction

(双向身份验证)演示项目说明如何将 TLS 与客户端和服务器之间的双向身份验证结合使用来建立与 HTTP 服务器的连接。coreHTTP此演示使用基于 mbedTLS 的传输接口实施来建立经服务器和客户端身份验证的 TLS 连接,并在 HTTP 中演示请求响应工作流程。

注意

要设置和运行 FreeRTOS 演示,请按照开始使用 FreeRTOS中的步骤操作。

Functionality

本演示使用演示如何完成以下操作的示例创建单个应用程序任务:

  • 连接到 AWS IoT 终端节点上的 HTTP 服务器。

  • 发送 POST 请求。

  • 接收响应。

  • 从服务器断开。

完成这些步骤后,演示将生成类似于以下屏幕截图的输出。

控制台生成类似于以下屏幕截图的输出。AWS IoT

以下示例是演示的结构。

int RunCoreHttpMutualAuthDemo( bool awsIotMqttMode, const char * pIdentifier, void * pNetworkServerInfo, void * pNetworkCredentialInfo, const IotNetworkInterface_t * pNetworkInterface ) { /* The transport layer interface used by the HTTP Client library. */ TransportInterface_t xTransportInterface; /* The network context for the transport layer interface. */ NetworkContext_t xNetworkContext = { 0 }; TransportSocketStatus_t xNetworkStatus; BaseType_t xIsConnectionEstablished = pdFALSE; /* Upon return, pdPASS will indicate a successful demo execution. * pdFAIL will indicate some failures occurred during execution. The * user of this demo must check the logs for any failure codes. */ BaseType_t xDemoStatus = pdPASS; /* Remove compiler warnings about unused parameters. */ ( void ) awsIotMqttMode; ( void ) pIdentifier; ( void ) pNetworkServerInfo; ( void ) pNetworkCredentialInfo; ( void ) pNetworkInterface; /**************************** Connect. ******************************/ /* Attempt to connect to the HTTP server. If connection fails, retry after a * timeout. The timeout value will be exponentially increased until either * the maximum number of attempts or the maximum timeout value is reached. * The function returns pdFAIL if the TCP connection cannot be established * with the broker after configured number of attempts. */ xDemoStatus = connectToServerWithBackoffRetries( prvConnectToServer, &xNetworkContext ); if( xDemoStatus == pdPASS ) { /* Set a flag indicating that a TLS connection exists. */ xIsConnectionEstablished = pdTRUE; /* Define the transport interface. */ xTransportInterface.pNetworkContext = &xNetworkContext; xTransportInterface.send = SecureSocketsTransport_Send; xTransportInterface.recv = SecureSocketsTransport_Recv; } else { /* Log error to indicate connection failure after all * reconnect attempts are over. */ LogError( ( "Failed to connect to HTTP server %.*s.", ( int32_t ) httpexampleAWS_IOT_ENDPOINT_LENGTH, democonfigAWS_IOT_ENDPOINT ) ); } /*********************** Send HTTP request.************************/ if( xDemoStatus == pdPASS ) { xDemoStatus = prvSendHttpRequest( &xTransportInterface, HTTP_METHOD_POST, httpexampleHTTP_METHOD_POST_LENGTH, democonfigPOST_PATH, httpexamplePOST_PATH_LENGTH ); } /**************************** Disconnect. ******************************/ /* Close the network connection to clean up any system resources that the * demo may have consumed. */ if( xIsConnectionEstablished == pdTRUE ) { /* Close the network connection. */ xNetworkStatus = SecureSocketsTransport_Disconnect( &xNetworkContext ); if( xNetworkStatus != TRANSPORT_SOCKET_STATUS_SUCCESS ) { xDemoStatus = pdFAIL; LogError( ( "SecureSocketsTransport_Disconnect() failed to close the network connection. " "StatusCode=%d.", ( int ) xNetworkStatus ) ); } } if( xDemoStatus == pdPASS ) { LogInfo( ( "Demo completed successfully." ) ); } return ( xDemoStatus == pdPASS ) ? EXIT_SUCCESS : EXIT_FAILURE; }

连接到 AWS IoT HTTP 服务器

connectToServerWithBackoffRetries 函数尝试建立与 HTTP 服务器的经相互身份验证的 TLS 连接。AWS IoT如果连接失败,它会在超时后重试。超时值以指数方式增加,直到达到最大尝试次数或达到最大超时值。函数提供指数递增的超时值,并在达到最大尝试次数时返回 RetryUtils_BackoffAndSleepRetryUtilsRetriesExhausted如果在配置的尝试次数后无法建立与代理的 TLS 连接,connectToServerWithBackoffRetries 函数将返回失败状态。

发送 HTTP 请求并接收响应

函数演示如何将 POST 请求发送到 prvSendHttpRequest HTTP 服务器。AWS IoT有关在 AWS IoT 中向 REST API 发出请求的更多信息,请参阅设备通信协议 - HTTPS。响应通过相同的 coreHTTP API 调用 HTTPClient_Send 接收。

static BaseType_t prvSendHttpRequest( const TransportInterface_t * pxTransportInterface, const char * pcMethod, size_t xMethodLen, const char * pcPath, size_t xPathLen ) { /* Return value of this method. */ BaseType_t xStatus = pdPASS; /* Configurations of the initial request headers that are passed to * #HTTPClient_InitializeRequestHeaders. */ HTTPRequestInfo_t xRequestInfo; /* Represents a response returned from an HTTP server. */ HTTPResponse_t xResponse; /* Represents header data that will be sent in an HTTP request. */ HTTPRequestHeaders_t xRequestHeaders; /* Return value of all methods from the HTTP Client library API. */ HTTPStatus_t xHTTPStatus = HTTPSuccess; configASSERT( pcMethod != NULL ); configASSERT( pcPath != NULL ); /* Initialize all HTTP Client library API structs to 0. */ ( void ) memset( &xRequestInfo, 0, sizeof( xRequestInfo ) ); ( void ) memset( &xResponse, 0, sizeof( xResponse ) ); ( void ) memset( &xRequestHeaders, 0, sizeof( xRequestHeaders ) ); /* Initialize the request object. */ xRequestInfo.pHost = democonfigAWS_IOT_ENDPOINT; xRequestInfo.hostLen = httpexampleAWS_IOT_ENDPOINT_LENGTH; xRequestInfo.pMethod = pcMethod; xRequestInfo.methodLen = xMethodLen; xRequestInfo.pPath = pcPath; xRequestInfo.pathLen = xPathLen; /* Set "Connection" HTTP header to "keep-alive" so that multiple requests * can be sent over the same established TCP connection. */ xRequestInfo.reqFlags = HTTP_REQUEST_KEEP_ALIVE_FLAG; /* Set the buffer used for storing request headers. */ xRequestHeaders.pBuffer = ucUserBuffer; xRequestHeaders.bufferLen = democonfigUSER_BUFFER_LENGTH; xHTTPStatus = HTTPClient_InitializeRequestHeaders( &xRequestHeaders, &xRequestInfo ); if( xHTTPStatus == HTTPSuccess ) { /* Initialize the response object. The same buffer used for storing * request headers is reused here. */ xResponse.pBuffer = ucUserBuffer; xResponse.bufferLen = democonfigUSER_BUFFER_LENGTH; LogInfo( ( "Sending HTTP %.*s request to %.*s%.*s...", ( int32_t ) xRequestInfo.methodLen, xRequestInfo.pMethod, ( int32_t ) httpexampleAWS_IOT_ENDPOINT_LENGTH, democonfigAWS_IOT_ENDPOINT, ( int32_t ) xRequestInfo.pathLen, xRequestInfo.pPath ) ); LogDebug( ( "Request Headers:\n%.*s\n" "Request Body:\n%.*s\n", ( int32_t ) xRequestHeaders.headersLen, ( char * ) xRequestHeaders.pBuffer, ( int32_t ) httpexampleREQUEST_BODY_LENGTH, democonfigREQUEST_BODY ) ); /* Send the request and receive the response. */ xHTTPStatus = HTTPClient_Send( pxTransportInterface, &xRequestHeaders, ( uint8_t * ) democonfigREQUEST_BODY, httpexampleREQUEST_BODY_LENGTH, &xResponse, 0 ); } else { LogError( ( "Failed to initialize HTTP request headers: Error=%s.", HTTPClient_strerror( xHTTPStatus ) ) ); } if( xHTTPStatus == HTTPSuccess ) { LogInfo( ( "Received HTTP response from %.*s%.*s...\n", ( int32_t ) httpexampleAWS_IOT_ENDPOINT_LENGTH, democonfigAWS_IOT_ENDPOINT, ( int32_t ) xRequestInfo.pathLen, xRequestInfo.pPath ) ); LogDebug( ( "Response Headers:\n%.*s\n", ( int32_t ) xResponse.headersLen, xResponse.pHeaders ) ); LogDebug( ( "Status Code:\n%u\n", xResponse.statusCode ) ); LogDebug( ( "Response Body:\n%.*s\n", ( int32_t ) xResponse.bodyLen, xResponse.pBody ) ); } else { LogError( ( "Failed to send HTTP %.*s request to %.*s%.*s: Error=%s.", ( int32_t ) xRequestInfo.methodLen, xRequestInfo.pMethod, ( int32_t ) httpexampleAWS_IOT_ENDPOINT_LENGTH, democonfigAWS_IOT_ENDPOINT, ( int32_t ) xRequestInfo.pathLen, xRequestInfo.pPath, HTTPClient_strerror( xHTTPStatus ) ) ); } if( xHTTPStatus != HTTPSuccess ) { xStatus = pdFAIL; } return xStatus; }