I am using AWS API Gateway / EC2 instance to host my backend api services like this:
My Backend is Nodejs / Express JS, and I am using socket.io
for real-time messaging:
const initializeExpress = (): void => {
const app = express();
let http = require("http").createServer(app);
let io = require("socket.io")(http, {
cors: {}
});
io.on("connection", function(socket: any) {
socket.on("hello", (res) => {
console.log('on hello: ', res);
});
});
const server = http.listen(parseInt(process.env.PORT) || 3001, function() {
console.log("listening on *:3001");
});
// register some middlewares for web socket
io.use((socket, next) => {
const username = socket.handshake.auth.username;
const organizationId = socket.handshake.auth.organizationId;
if (!username || !organizationId) {
return next(new Error("invalid username or organizationId"));
}
socket.username = username;
socket.organizationId = organizationId;
next();
});
app.use(httpLogger);
app.use(cors());
app.use(express.json());
app.use(express.urlencoded());
app.use(express.urlencoded({ extended: true }));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, 'build')));
app.use(addRespondToResponse);
attachPublicRoutes(app);
// validate incoming request has valid username
app.use('/', authenticateUser);
// all api endpints;
attachPrivateRoutes(app);
app.use((req, _res, next) => next(new RouteNotFoundError(req.originalUrl)));
// a place for all errors;
app.use(handleError);
};
The above code works when testing in local environment. To be precise, when the backend is running on 127.0.0.1:3001
, the frontend, also run locally, can establish WebSocket connection with it and things are working smoothly.
However, when I move to the AWS API Gateway configuration above, all other api endpoints are working (meaning that the API Gateway is configured with success), it is just the websocket request is failing with 404
Error:
error: User undefined got Error on NLB-myapp-internal-1234123.elb.ap-northeast-1.amazonaws.com/socket.io?EIO=4&t=Nv2sCMO&transport=polling: Error: Route '/socket.io?EIO=4&t=Nv2sCMO&transport=polling' does not exist. Error: Route '/socket.io?EIO=4&t=Nv2sCMO&transport=polling' does not exist.
The message Error: Route '/socket.io?EIO=4&t=Nv2sCMO&transport=polling' does not exist.
keeps appearing on and on...
Below is my Restful API created in AWS API Gateway:
It is configured as a Proxy Integration. And we can see that the request is indeed proxied to the EC2 instance port running the Nodejs/Express service. It is just that the Route /socket.io
is missing.
I have found some related answers: https://stackoverflow.com/a/24811468/3703783 https://stackoverflow.com/a/16982780/3703783
However, they are not helping because I have done what they suggested by setting the socket.io in Express as:
const app = express();
let http = require("http").createServer(app);
let io = require("socket.io")(http, {
cors: {}
});
const server = http.listen(parseInt(process.env.PORT) || 3001, function() {
console.log("listening on *:3001");
});
By the way, in the local dev environment (without api gateway), when the request is successful delivered to the target port, things are OK.
In the AWS API Gateway architecture, why is the request successful delivered to the target port but still complaining that Route /socket.io
does not exist?
What am I missing here?