API Gateway WSS Endpoint not found

0

I've created a WSS chat app using the sample that comes with the AWS dotnet lambda templates. My web front end can connect ok and it creates a record in dynamo but when I try to broadcast a message to all connections I get the following error:

`Name or service not known (execute-api.ap-southeast-2.amazonaws.com:443) `

I'm using the following code to set it:

  var protocol = "https";
  //var protocol = "wss";
  
  var domainName = request.RequestContext.DomainName;
  //var domainName = "ID HERE.execute-api.ap-southeast-2.amazonaws.com";
  
  var stage = request.RequestContext.Stage;
  // var stage = "";
  //var stage = "test";
  //var stage = "test/@connections";
  
  var endpoint = $"{protocol}://{domainName}/{stage}";

and it logs the following:

API Gateway management endpoint: https://ID HERE.execute-api.ap-southeast-2.amazonaws.com/test

Ive tried all the combinations and a custom domain. Im thinking that ap-southeast-2 does not support wss ? Or ... ?? Been stuck on this for a while now. About ready to give up. Anyone got any ideas??

Update: Heres the code for sending the message - it just an updated version of the sample. From the startup:

  public Functions()
  {
    DDBClient = new AmazonDynamoDBClient();

    // Grab the name of the DynamoDB from the environment variable setup in the CloudFormation template serverless.template
    if (Environment.GetEnvironmentVariable(TABLE_NAME_ENV) == null)
    {
      throw new ArgumentException($"Missing required environment variable {TABLE_NAME_ENV}");
    }

    ConnectionMappingTable = Environment.GetEnvironmentVariable(TABLE_NAME_ENV) ?? "";

    this.ApiGatewayManagementApiClientFactory = (Func<string, AmazonApiGatewayManagementApiClient>)((endpoint) =>
    {
      return new AmazonApiGatewayManagementApiClient(new AmazonApiGatewayManagementApiConfig
      {
        ServiceURL = endpoint,
        
        RegionEndpoint = RegionEndpoint.APSoutheast2, // without this I get Credential errors
        LogResponse = true,  // dont see anything extra with these
        LogMetrics = true,
        DisableLogging = false
      });
    });
  }

And the SendMessageFunction:

    try
    {
      // Construct the API Gateway endpoint that incoming message will be broadcasted to.
      var protocol = "https";
      //var protocol = "wss";
      
      var domainName = request.RequestContext.DomainName;
      //var domainName = "?????.execute-api.ap-southeast-2.amazonaws.com";
      
      var stage = request.RequestContext.Stage;
      // var stage = "";
      //var stage = "test";
      //var stage = "test/@connections";
      
      var endpoint = $"{protocol}://{domainName}/{stage}";
      
      context.Logger.LogInformation($"API Gateway management endpoint: {endpoint}");
      
      JObject message = JObject.Parse(request.Body);
      context.Logger.LogInformation(request.Body);


      if (!GetRecipient(message, context, out WSMessageRecipient? recipient))
      {
        context.Logger.LogError($"Invalid or empty WSMessageRecipient");
        return new APIGatewayProxyResponse
        {
          StatusCode = (int)HttpStatusCode.BadRequest, Body = "Nothing to do or invalid request"
        };
      }
      
      if (!GetData(message, context, out string? data))
      {
        context.Logger.LogError($"Invalid or empty WSSendMessage");
        return new APIGatewayProxyResponse
        {
          StatusCode = (int)HttpStatusCode.BadRequest, Body = "Nothing to do or invalid request"
        };
      }

      var stream = new MemoryStream(UTF8Encoding.UTF8.GetBytes(data!));
      
      if (stream.Length == 0)
      {
        context.Logger.LogError($"Empty Stream");
        return new APIGatewayProxyResponse
        {
          StatusCode = (int)HttpStatusCode.BadRequest, Body = "Empty data stream"
        };
      }

      // List all of the current connections. In a more advanced use case the table could be used to grab a group of connection ids for a chat group.
      ScanResponse scanResponse = await GetConnectionItems(recipient);

      // Construct the IAmazonApiGatewayManagementApi which will be used to send the message to.
      var apiClient = ApiGatewayManagementApiClientFactory(endpoint);

      context.Logger.LogInformation($"Table scan of {ConnectionMappingTable} got {scanResponse.Items.Count} records.");
      
      // Loop through all of the connections and broadcast the message out to the connections.
      var count = 0;
      foreach (var item in scanResponse.Items)
      {
        var connectionId = item[ConnectionIdField].S;

        context.Logger.LogInformation($"Posting to connection {count}: {connectionId}");

        var postConnectionRequest = new PostToConnectionRequest
        {
          ConnectionId = connectionId, Data = stream
        };

        try
        {
          stream.Position = 0;
          await apiClient.PostToConnectionAsync(postConnectionRequest);
          context.Logger.LogInformation($"Posted to connection {count}: {connectionId}");
          count++;
        }
        catch (AmazonServiceException e)
        {
          // API Gateway returns a status of 410 GONE then the connection is no
          // longer available. If this happens, delete the identifier
          // from our DynamoDB table.
          if (e.StatusCode == HttpStatusCode.Gone)
          {
            context.Logger.LogInformation($"Deleting gone connection: {connectionId}");
            var ddbDeleteRequest = new DeleteItemRequest
            {
              TableName = ConnectionMappingTable,
              Key = new Dictionary<string, AttributeValue>
              {
                {ConnectionIdField, new AttributeValue {S = connectionId}}
              }
            };

            await DDBClient.DeleteItemAsync(ddbDeleteRequest);
          }
          else
          {
            context.Logger.LogError(
              $"Error posting message to {connectionId}: {e.Message}");
            context.Logger.LogInformation(e.StackTrace);
          }
        }
        catch (Exception ex)
        {
          context.Logger.LogError($"Bugger, something fecked up: {ex.Message}");
          context.Logger.LogInformation(ex.StackTrace);
        }
      }

      return new APIGatewayProxyResponse
      {
        StatusCode = (int)HttpStatusCode.OK, Body = "Data sent to " + count + " connection" + (count == 1 ? "" : "s")
      };
    }
    catch (Exception e)
    {
      context.Logger.LogInformation("Error Sending Message: " + e.Message);
      context.Logger.LogInformation(e.StackTrace);
      return new APIGatewayProxyResponse
      {
        StatusCode = (int)HttpStatusCode.InternalServerError, Body = $"Failed to send message: {e.Message}"
      };
    }
2 Antworten
0
Akzeptierte Antwort

Solved it by adding the credentials when creating the Api Client. Dont ask me why - it should be getting this from the role I thought:

    this.ApiGatewayManagementApiClientFactory = (Func<string, AmazonApiGatewayManagementApiClient>)((endpoint) =>
    {
      AWSCredentials awsCredentials = new EnvironmentVariablesAWSCredentials();
      return new AmazonApiGatewayManagementApiClient(awsCredentials, new AmazonApiGatewayManagementApiConfig
      {
        ServiceURL = endpoint
      });
    });
beantwortet vor 2 Jahren
0

Client should connect to wss://API ID.execute-api.REGION.amazonaws.com/STAGE.

When the client wants to send messages on the connection it should send requests to: https://API ID.execute-api.REGION.amazonaws.com/STAGE/@connections.

As far as I know, websockets are supported there, especially if your client is able to connect.

profile pictureAWS
EXPERTE
Uri
beantwortet vor 2 Jahren
  • I'll try that again but pretty sure I did already. If I use a custom domain then I dont need /stage/ ??

  • Confirmed, that doesnt work either.

  • How does your sending code looks like?

  • Updated. Thanks for helping!!!

Du bist nicht angemeldet. Anmelden um eine Antwort zu veröffentlichen.

Eine gute Antwort beantwortet die Frage klar, gibt konstruktives Feedback und fördert die berufliche Weiterentwicklung des Fragenstellers.

Richtlinien für die Beantwortung von Fragen