D:\code_gitee\fastapi-socketio-example-main\fastapi-socketio-example-main\app.py
| |
| import os |
| import pathlib |
| import secrets |
| import time |
| from typing import Optional |
| |
| import socketio |
| from fastapi import FastAPI |
| from fastapi.middleware.cors import CORSMiddleware |
| from fastapi.param_functions import Cookie, Depends |
| from fastapi.params import Form |
| from fastapi.staticfiles import StaticFiles |
| from fastapi.templating import Jinja2Templates |
| from starlette.middleware.sessions import SessionMiddleware |
| from starlette.requests import Request |
| from starlette.responses import HTMLResponse, JSONResponse, RedirectResponse, Response |
| |
| SECRET_KEY = os.environ.get("SECRET_KEY", "ef4ac4e2a33e4d9e0bb34200349e3544") |
| |
| templates = Jinja2Templates(directory=pathlib.Path(__file__).parent / "templates") |
| |
| |
| fake_users_db = { |
| "johndoe": { |
| "username": "johndoe", |
| "full_name": "John Doe", |
| "email": "johndoe@example.com", |
| "hashed_password": "fakehashedsecret", |
| "disabled": False, |
| }, |
| "alice": { |
| "username": "alice", |
| "full_name": "Alice Wonderson", |
| "email": "alice@example.com", |
| "hashed_password": "123", |
| "disabled": True, |
| }, |
| } |
| |
| |
| class RequiresLoginException(Exception): |
| pass |
| |
| |
| app = FastAPI() |
| sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins=[]) |
| app.mount("/ws", socketio.ASGIApp(sio)) |
| app.add_middleware(SessionMiddleware, secret_key=SECRET_KEY) |
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins=["*"], |
| allow_credentials=True, |
| allow_methods=["*"], |
| allow_headers=["*"], |
| ) |
| app.mount( |
| "/static", |
| StaticFiles(directory=pathlib.Path(__file__).parent / "templates"), |
| name="static", |
| ) |
| |
| |
| |
| |
| @app.exception_handler(RequiresLoginException) |
| async def exception_handler(*args, **kwargs) -> Response: |
| return RedirectResponse(url="/", status_code=303) |
| |
| |
| def verify_session_id(request: Request, session_id: Optional[str] = Cookie(...)): |
| """Verify the session_id in the fake db. |
| If it doesn't exist raise an exception to redirect to Login page""" |
| username = request.session.get(session_id) |
| if username not in fake_users_db: |
| |
| |
| raise RequiresLoginException |
| return username |
| |
| |
| @app.get("/view") |
| async def view(request: Request, username: str = Depends(verify_session_id)): |
| await sio.emit("message", "hello universe") |
| return templates.TemplateResponse( |
| "view.html", |
| { |
| "request": request, |
| "current_user": username, |
| "start_time": request.session.get("start_time", int(time.time())), |
| "PORT": os.environ.get("PORT", 8000), |
| }, |
| ) |
| |
| |
| @app.get("/") |
| def index(request: Request): |
| |
| |
| if request.session: |
| return RedirectResponse(url="/view", status_code=303) |
| return templates.TemplateResponse("index.html", {"request": request}) |
| |
| |
| @app.post("/login") |
| async def login(request: Request, username: str = Form(...), password: str = Form(...)): |
| """Get `username` and `password` from form data and authenticate the user |
| If username doesn't exist, redirect to Login page. |
| Else continue to `/view` page |
| """ |
| |
| |
| if username not in fake_users_db: |
| response = RedirectResponse(url="/", status_code=303) |
| return response |
| |
| |
| response = RedirectResponse(url="/view", status_code=303) |
| session_id = secrets.token_hex(16) |
| request.session.update( |
| { |
| session_id: username, |
| "start_time": int(time.time()), |
| "username": username, |
| } |
| ) |
| response.set_cookie("session_id", session_id) |
| return response |
| |
| |
| @app.get("/logout", name="logout") |
| async def logout(request: Request, username: str = Depends(verify_session_id)): |
| """Logout and redirect to Login screen""" |
| request.session.clear() |
| response = RedirectResponse(url="/", status_code=303) |
| response.set_cookie("session_id", None) |
| await sio.emit("logout", username) |
| return response |
| |
| @app.get('/student') |
| async def student(): |
| return {'data':'alice'} |
| |
| @sio.event |
| async def connect(sid, environ): |
| session = environ["asgi.scope"]["session"] |
| await sio.emit("new user", session) |
| |
| |
| @sio.event |
| async def message(sid, data): |
| await sio.emit("message", data, room=sid) |
| |
| @sio.on('join') |
| async def ping_message(sid,data): |
| print(data) |
| await sio.emit("join", 'hello!~~ from server', room=sid) |
| |
| |
| |
D:\code_gitee\fastapi-socketio-example-main\fastapi-socketio-example-main\main.py
| import uvicorn |
| if __name__ == '__main__': |
| uvicorn.run("app:app",host="127.0.0.1", port=9998, reload=True) |
| |
D:\code_gitee\fastapi-socketio-example-main\fastapi-socketio-example-main\templates\index.html
| <html> |
| |
| <head> |
| <title>Index</title> |
| <style> |
| </style> |
| </head> |
| |
| <body> |
| <div class="form-center"> |
| <form action="/login" method="post"> |
| <input type="text" name="username" placeholder="username" required> |
| <br/> <br/> |
| <input type="password" name="password" placeholder="password" required> |
| <br/> <br/> |
| <input type="submit" value="Login"> |
| </form> |
| </div> |
| </body> |
| |
| </html> |
D:\code_gitee\fastapi-socketio-example-main\fastapi-socketio-example-main\templates\view.html
| <html> |
| |
| <head> |
| <title>View</title> |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.4.0/socket.io.js" integrity="sha512-nYuHvSAhY5lFZ4ixSViOwsEKFvlxHMU2NHts1ILuJgOS6ptUmAGt/0i5czIgMOahKZ6JN84YFDA+mCdky7dD8A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> |
| </head> |
| <body> |
| <p>Hello {{ current_user }}</p> |
| <span id='ct'></span> |
| <br/> |
| <button type="button"><a id="logoutBtn" href="{{ url_for('logout') }}" style="text-decoration: none;">Logout</a></button> |
| <br /> |
| <i>Note</i> <br/> |
| This msg box is just a convenient way if the web socket works [for testing] |
| <br /> |
| <input id="textInput" placeholder="message"> |
| <button id="sendBtn">Send</button> |
| |
| <ul> |
| |
| </ul> |
| |
| </body> |
| <script defer type="text/javascript"> |
| const startTime = {{ start_time }} |
| const currentUser = '{{ current_user }}' |
| const PORT = '{{ PORT }}' |
| function display_c() { |
| var refresh = 1000; |
| mytime = setTimeout('display_ct()', refresh) |
| } |
| |
| function display_ct() { |
| var x = new Date() |
| document.getElementById('ct').innerHTML = x; |
| display_c(); |
| } |
| |
| |
| if (window.location.protocol == "https:") { |
| var ws_scheme = "wss://"; |
| } else { |
| var ws_scheme = "ws://" |
| }; |
| |
| const socket = io(ws_scheme + location.host, {path: '/ws/socket.io/'}); |
| |
| socket.on('new user', data => { |
| socket.user = data.username |
| console.log({ data }); |
| }); |
| |
| socket.on('message', text => { |
| const el = document.createElement('li'); |
| el.innerHTML = text + socket.user; |
| document.querySelector('ul').appendChild(el); |
| }); |
| |
| |
| document.getElementById('sendBtn').onclick = () => { |
| const text = document.getElementById('textInput').value; |
| socket.emit('message', text) |
| } |
| |
| const logoutBtn = document.getElementById('logoutBtn') |
| |
| socket.on('logout', userName => { |
| if ( currentUser === userName) { |
| socket.disconnect(); |
| logoutBtn.click(); |
| } |
| }); |
| |
| display_ct(); |
| </script> |
| </html> |
| |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!