Как программно подключиться к AWS websocket API Gateway - PullRequest
0 голосов
/ 21 апреля 2019

Я пытаюсь реализовать обмен сообщениями между пользователями на своем веб-сайте, используя шлюз API веб-сокета AWS.В каждом руководстве / документации, на которые я смотрю, говорится, что для проверки соединения со шлюзом используется wscat.Я нахожусь в точке, где я могу подключиться к шлюзу API и отправлять сообщения между клиентами, используя wscat, но изо всех сил пытаюсь заставить его работать программно из моего кода TS.

Что я хочу сделать, это сделать вызов API длякак только пользователь входит в систему, веб-сокет API-шлюза может отправлять сообщения в любой момент.Я использую серверные для моего бэкэнда и Angular 6 для внешнего интерфейса.Я прочитал, что мне нужно сделать POST запрос на https://{api-id}.execute-api.us-east-1.amazonaws.com/{stage}/@connections/{connection_id} для отправки сообщений через соединение через веб-сокет, но у меня возникают проблемы с использованием машинописи в сервисе, который я создал для соединения / получения идентификатора соединения.

Я делаю второй вызов API после того, как пользователь успешно вошел в систему, чтобы открыть соединение со шлюзом websocket api.Я попытался вызвать функцию, которая отправляет пост-запрос без тела (не уверен, что я отправлю в теле запроса, так как я подключился к нему только с помощью инструмента wscat) по URL-адресу, который я получаю после развертывания моего бессерверного кода.Я также попытался сделать запрос POST к URL-адресу https: //, который я вижу в консоли AWS после развертывания шлюза API вручную.

base.service.ts

protected getBaseSocketEndpoint(): string {
        // 'wss://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev' <-- tried this too
        return 'https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/@connections';
    }

authentication.service.ts

this.authService.login(username, password).pipe(first()).subscribe(
            (response) => {
                console.log(response);
                this.authService.setCookie('userId', response.idToken.payload.sub);
                this.authService.setCookie('jwtToken', response.idToken.jwtToken);
                this.authService.setCookie('userEmail', response.idToken.payload.email);
                this.authService.setCookie('refreshToken', response.refreshToken.token);

                this.toastr.success('Login successful. Redirecting to your dashboard.', 'Success!', {
                    timeOut: 1500
                });

                this.authService.connectToWebSocket(response.idToken.payload.sub).pipe(first()).subscribe(
                    response => {
                        console.log(response);
                    }
                );

                this.routerService.routeToUserDashboard();
            },
            (error) => {
                // const errorMessage = JSON.parse(error._body).message;
                this.toastr.error("Incorrect username and password combination.", 'Error!', {
                    timeOut: 1500
                });
            }
        );

authentication.service.ts extends BaseService

public connectToWebSocket(userId: string): Observable<any> {
        const body = {
            userId: userId
        };

        console.log('calling connectToWebSocket()..');
        return this.http.post(this.getBaseSocketEndpoint(), body).pipe(map(response => {
            console.log(response);
        }));
    }

serverless.yaml

functions:
  connectionHandler:
    handler: connectionHandler.connectionHandler
    events:
      - websocket:
          route: $connect
          cors: true
      - websocket:
          route: $disconnect
          cors: true
  defaultHandler:
    handler: connectionHandler.defaultHandler
    events:
      - websocket:
          route: $default
          cors: true
  sendMessageHandler:
    handler: messageHandler.sendMessageHandler
    events:
      - websocket:
          route: sendMessage
          cors: true

connectionHandler.js (лямбда)

const success = {
  statusCode: 200,
  headers: { "Access-Control-Allow-Origin": "*" },
  body: "everything is alright"
};

module.exports.connectionHandler = (event, context, callback) => {
  var connectionId = event.requestContext.connectionId;
  if (event.requestContext.eventType === "CONNECT") {
    addConnection(
      connectionId,
      "b72656eb-db8e-4f32-a6b5-bde4943109ef",
      callback
    )
      .then(() => {
        console.log("Connected!");
        callback(null, success);
      })
      .catch(err => {
        callback(null, JSON.stringify(err));
      });
  } else if (event.requestContext.eventType === "DISCONNECT") {
    deleteConnection(
      connectionId,
      "b72656eb-db8e-4f32-a6b5-bde4943109ef",
      callback
    )
      .then(() => {
        console.log("Disconnected!");
        callback(null, success);
      })
      .catch(err => {
        callback(null, {
          statusCode: 500,
          body: "Failed to connect: " + JSON.stringify(err)
        });
      });
  }
};

// THIS ONE DOESNT DO ANYHTING
module.exports.defaultHandler = (event, context, callback) => {
  callback(null, {
    statusCode: 200,
    body: "default handler was called."
  });
};

const addConnection = (connectionId, userId, callback) => {
  const params = {
    TableName: CHATCONNECTION_TABLE,
    Item: {
      connectionId: connectionId,
      userId: userId
    }
  };

  var response;
  return dynamo
    .put(params, function(err, data) {
      if (err) {
        errorHandler.respond(err, callback);
        return;
      } else {
        response = {
          statusCode: 200,
          headers: { "Access-Control-Allow-Origin": "*" },
          body: JSON.stringify(data)
        };
        callback(null, response);
      }
    })
    .promise();
};

const deleteConnection = (connectionId, userId, callback) => {
  const params = {
    TableName: CHATCONNECTION_TABLE,
    Key: {
      connectionId: connectionId,
      userId: userId
    }
  };

  var response;
  return dynamo
    .delete(params, function(err, data) {
      if (err) {
        errorHandler.respond(err, callback);
        return;
      } else {
        response = {
          statusCode: 200,
          headers: { "Access-Control-Allow-Origin": "*" },
          body: JSON.stringify(data)
        };
        callback(null, response);
      }
    })
    .promise();
};

Ожидается: вызов API POST и открытие постоянного соединения с шлюзом Websocket API.

Фактически: невозможно подключиться через вызов API выше.Я получаю 403 в консоли с сообщением:

Доступ к XMLHttpRequest по адресу https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/@connections 'изorigin 'http://localhost:4200' было заблокировано политикой CORS: Ответ на запрос предварительной проверки не проходит проверку контроля доступа: в запрошенном ресурсе отсутствует заголовок' Access-Control-Allow-Origin '.

Не уверен, почему я получаю ошибку CORS, когда у меня включен CORS в моем файле без сервера.

1 Ответ

0 голосов
/ 23 апреля 2019

У меня была такая же проблема, и я наконец понял, что обычно не должно быть такого сообщения об ошибке CORS с websockets:

Почему нет политики одного и того же происхождения для WebSockets? Почему я могу подключиться к ws: // localhost?

Пропуск клиентской библиотеки "socket.io" и использование "vanilla websockets" помогли мне.

В вашем случае я бы проверил библиотеки за "connectToWebSocket".

...