当前位置: 首页 > 知识库问答 >
问题:

如何以编程方式连接到AWS websocket API网关

郎飞航
2023-03-14

我正在尝试通过利用AWS的websocket api网关在我的网站上实现用户之间的消息传递。我看到的每个指南/文档都说要使用wscat测试到网关的连接。我现在可以连接到api网关并使用wscat在客户机之间发送消息,但我正努力通过ts代码使它以编程方式工作。

我想做的是在用户登录后对websocket api网关进行api调用,这样他们就可以在任何时候发送消息。我的后端使用无服务器,前端使用Angular 6。我了解到,我需要向https://{api-id}.execute-api.us-east-1.amazonaws.com/{stage}/@connections/{connection_id}发出post请求,以便通过websocket连接发送消息,但在我创建的用于连接/获取连接ID的服务中使用typescript时遇到了问题。

用户成功登录以打开到websocket API网关的连接之后,我正在进行第二次API调用。我尝试调用一个函数,该函数将一个没有正文的post请求(不确定我将在请求正文中发送什么,因为我只是使用wscat工具连接到它)发送到部署无服务器代码后获得的URL。在手动部署API网关之后,我还尝试向AWS控制台中看到的https://URL发出POST请求。

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扩展基本服务

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);
        }));
    }

无服务器.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(lambda)

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();
};

预期:触发POST api调用并打开与Websocket api网关的持久连接。

实际情况:无法通过上面的API调用连接。我在控制台中得到一个403,其中有消息:

CORS策略已阻止从源“http://localhost:4200”访问“https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/@connections”得XMLHttpRequest:对预飞行请求得响应未通过访问控制检查:请求得资源上没有“access-control-allog-origin”标头.

不确定为什么我在我的无服务器文件中启用了CORS时会出现CORS错误。

共有1个答案

翁宏茂
2023-03-14

我也有类似的问题。您可以使用所有的socket.io-client goodness。但必须将“传输”选项设置为:

 let socket = io(url, {
        reconnectionDelayMax: 1000,
        transports: ["websocket"],
      });

默认值为

transports: ["polling", "websocket"],

所以您的应用程序将启动轮询并导致CORS错误。文档中并不清楚,但这里有一个有用的链接。

请参阅“基础工程.io客户机的可用选项:”下。

 类似资料:
  • 以同样的方式,我想为OTG做这件事。

  • 我实际上是在编程一些东西,不让用户访问Android原生wifi连接页面,所以我在我的Android应用程序中编程。它扫描可用的无线网络,将其显示在列表视图中,然后单击要连接的网络。 事实上,除了我的连接功能之外,一切都很好,这使得我的应用程序崩溃,所以如果你有任何想法...下面是代码(这是用户输入网络通行证后调用的函数)和堆栈跟踪: 堆栈跟踪:

  • 问题内容: 我必须将文件上传到服务器,该服务器仅使用文件上传按钮(通过http)公开jsf网页。我必须自动执行一个过程(作为Java独立过程完成),该过程生成一个文件并将该文件上传到服务器。可悲的是,必须将文件上传到的服务器不提供FTP或SFTP。有没有办法做到这一点? 谢谢,里奇 问题答案: 以编程方式提交JSF生成的表单时,需要确保考虑以下三点: 维护HTTP会话(肯定是网站是否启用了JSF服

  • 目的尝试连接或切换到特定的WiFi网络,无需任何人为干预(用户名和密码除外)。 代码片段 主要活动。kt 类主活动:AppCompat活动(){ } AndroidManifest。xml权限 使用此代码,设备能够连接到WiFi网络,但需要手动关闭和打开WiFi。必须有更好的方法来连接或切换到特定的WiFi网络,而无需任何手动操作。 当前流程: 运行应用程序并单击主屏幕上的按钮连接到WiFi。 转

  • 我正在用jsPlumb构建一个UI,因为我有多个可以连接在一起的盒子。每个框有1个目标和3个源,使用对同一个框DOM元素调用的和方法生成。 每个源通过将其连接到方框不同部分的过滤器属性进行区分: 只能在一个盒子的源和另一个盒子的目标之间进行连接。目标锚点是连续的。 这种安排非常适合我需要的东西,只要处理盒子和拖放连接。 当我想从JSON对象重新创建保存的UI时,问题就出现了。我可以毫无问题地重新创

  • 我的要求是,我使用jsplumb.addEndPoint为两个名为“container0”和“container1”的容器添加两个endpoint。 现在我需要通过编程方式使用连接器链接两个endpoint,但是jsplump.connect创建了一个新endpoint并进行连接,而不是使用我使用jsplump.addEndpoint创建的endpoint。 我如何连接这两个endpoint?此外