[英]How to programmatically connect to AWS websocket API Gateway
我正在嘗試利用 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 的服務中使用打字稿時遇到問題。
在用戶成功登錄以打開與 websocket api 網關的連接后,我正在進行第二次 API 調用。 我嘗試調用一個函數,該函數發出一個沒有正文的 post 請求(不確定我會在請求正文中發送什么,因為我只使用 wscat 工具連接到它)到部署我的無服務器代碼后得到的 URL。 在手動部署 API 網關后,我還嘗試向在 AWS 控制台中看到的 https:// URL 發出 POST 請求。
基礎.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';
}
身份驗證.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 擴展了 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);
}));
}
無服務器.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 策略已阻止在“ https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/@connections ”處訪問 XMLHttpRequest,來自源“ http://localhost:4200 ”:響應預檢請求未通過訪問控制檢查:請求的資源上不存在“Access-Control-Allow-Origin”標頭。
當我在無服務器文件中啟用 CORS 時,不知道為什么會出現 CORS 錯誤。
我有一個類似的問題。 您可以使用 socket.io-client 的所有優點。 但是您必須將選項傳輸設置為:
let socket = io(url, {
reconnectionDelayMax: 1000,
transports: ["websocket"],
});
默認是
transports: ["polling", "websocket"],
因此,您的應用程序將開始輪詢並導致 CORS 錯誤。 文檔中不是很清楚,但這里有一個有用的鏈接。
查看“底層 Engine.IO 客戶端的可用選項:”。
我遇到了同樣的問題,最后發現,通常情況下,websockets 不應該有這樣的 CORS 錯誤消息:
為什么 WebSockets 沒有同源策略? 為什么我可以連接到 ws://localhost?
跳過客戶端庫“socket.io”並使用“vanilla websockets”幫助了我。
在你的情況下,我會檢查“connectToWebSocket”背后的庫。
service: realtime-websocket-test
provider:
name: aws
stage: ${opt:stage, 'dev'}
runtime: python3.8
region: ${opt:region, 'ap-south-1'}
memorySize: 128
timeout: 300
functions:
connect:
handler: handler.lambda_handler
events:
- websocket:
route: $connect
- websocket:
route: $disconnect
- websocket:
route: $default
import time
import json
import boto3
def lambda_handler(event, context):
print(event)
event_type = event["requestContext"]["eventType"]
if event_type == "CONNECT" or event_type == "DISCONNECT":
response = {'statusCode': 200}
return response
elif event_type == "MESSAGE":
connection_id = event["requestContext"]["connectionId"]
domain_name = event["requestContext"]["domainName"]
stage = event["requestContext"]["stage"]
message = f'{domain_name}: {connection_id}'.encode('utf-8')
api_client = boto3.client('apigatewaymanagementapi', endpoint_url = f"https://{domain_name}/{stage}")
for _ in range(5):
api_client.post_to_connection(Data=message,
ConnectionId=connection_id)
time.sleep(5)
response = {'statusCode': 200}
return response
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.