I have a Python backend (built with FastAPI) and a JavaScript frontend (built with ReactJS). I created a websocket route in the backend, and a websocket component in the frontend. When both servers are run locally, the websocket works as expected. However, when I deploy to Azure Web App, the websocket cannot open the connection to the backend. Both my Azure Web App instances are using Linux and Python 3.9/NodeJS 18 LTS in their respective enviroments. Everything else in the application works as exppected.
Here is my frontend websocket code (I replaced the real domain address with MYDOMAIN):
import React, { useEffect } from "react";
const WebSocketExample = () => {
const socket = new WebSocket("wss://MYDOMAIN/ws/");
useEffect(() => {
socket.onopen = function (event) {
console.log("WebSocket connected");
};
socket.onmessage = function (event) {
console.log("Received message:", event.data);
};
socket.onclose = function (event) {
console.log("WebSocket closed");
};
return () => {
socket.close();
};
}, [socket]);
function sendEvent() {
const eventData = "Event data";
socket.send(eventData);
console.log("Sent event:", eventData);
}
return (
<div>
<h1>WebSocket Example</h1>
<button onClick={sendEvent}>Send Event</button>
</div>
);
};
export default WebSocketExample;
And my backend route:
from app.routes.crud import crud_router
from app.routes.login import login_router
from app.routes.security import security_router
from app.routes.configs import configs_router
from setup import app, root_logger
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi import WebSocket
from fastapi.responses import JSONResponse, HTMLResponse
import uvicorn
app.include_router(login_router)
app.include_router(crud_router)
app.include_router(security_router)
app.include_router(configs_router)
app = FastAPI()
app.add_middleware( # necessary to allow requests from local services
CORSMiddleware,
allow_methods=["*"],
allow_headers=["*"],
allow_origins=[
'http://localhost:3000',
'https://MYDOMAIN',
],
allow_credentials=True)
connected_clients = set()
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
# Accept WebSocket connection
await websocket.accept()
# Add client to the connected clients set
connected_clients.add(websocket)
try:
while True:
# Receive event data from the client
event_data = await websocket.receive_text() + 'wow'
root_logger.info(f"WEBSOCKET received event data: {event_data}")
# Process the event data (e.g., validate, update state)
# Broadcast the event data to all connected clients
for client in connected_clients:
await client.send_text(event_data)
root_logger.info(f"WEBSOCKET has sent data: {event_data}")
except Exception as e:
root_logger.error(f"WEBSOCKET has error: {e}")
finally:
# Remove client from the connected clients set
connected_clients.remove(websocket)
root_logger.info(f"WEBSOCKET has removed client: {websocket}")
if __name__ == '__main__':
uvicorn.run('main:app', reload=True, port=8000)
I get the following printed on the browser's console:
webs.js:7 WebSocket connection to 'wss://MYDOMAIN/ws/' failed: WebSocketExample @ webs.js:7 renderWithHooks @ react-dom.development.js:16305 mountIndeterminateComponent @ react-dom.development.js:20074 beginWork @ react-dom.development.js:21587 beginWork$1 @ react-dom.development.js:27426 performUnitOfWork @ react-dom.development.js:26557 workLoopSync @ react-dom.development.js:26466 renderRootSync @ react-dom.development.js:26434 performConcurrentWorkOnRoot @ react-dom.development.js:25738 workLoop @ scheduler.development.js:266 flushWork @ scheduler.development.js:239 performWorkUntilDeadline
I cannot for the life of me know what is wrong. I have scoured the internet and the AI's for answers, but there are surprisingly few mentions of this problem using this stack.
Thanks in advance for any answers.
EDIT: upon further testing I was able to setup a dummy Backend which succesfully tested for websocket connection. I used no CORS, so I am thinking that somehow FastAPI's CORS Middleware is interfering with the websocket connection.
I will now attempt removing CORS from my code, and seeing if it performs as expected. If that works, I will then attempt to setup Azure's CORS.