기술나눔

FastAPI 학습 로드(44) WebSocket

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

이전 분석은 모두 http 요청을 기반으로 했기 때문에 웹소켓이 이를 지원할 수 있다면 대답은 '예'입니다. 이를 구현하는 방법을 살펴보겠습니다.

  1. from fastapi import WebSocket, FastAPI
  2. from fastapi.responses import HTMLResponse
  3. app = FastAPI()
  4. html = """
  5. <!DOCTYPE html>
  6. <html>
  7. <head>
  8. <title>Chat</title>
  9. </head>
  10. <body>
  11. <h1>WebSocket 聊天</h1>
  12. <form action="" onsubmit="sendMessage(event)">
  13. <input type="text" id="messageText" autocomplete="off"/>
  14. <button>Send</button>
  15. </form>
  16. <ul id='messages'>
  17. </ul>
  18. <script>
  19. var ws = new WebSocket("ws://localhost:8000/ws");
  20. ws.onmessage = function(event) {
  21. var messages = document.getElementById('messages')
  22. var message = document.createElement('li')
  23. var content = document.createTextNode(event.data)
  24. message.appendChild(content)
  25. messages.appendChild(message)
  26. };
  27. function sendMessage(event) {
  28. var input = document.getElementById("messageText")
  29. ws.send(input.value)
  30. input.value = ''
  31. event.preventDefault()
  32. }
  33. </script>
  34. </body>
  35. </html>
  36. """
  37. @app.get("/")
  38. async def get_page():
  39. return HTMLResponse(html)
  40. @app.websocket("/ws")
  41. async def websocket_endpoint(websocket: WebSocket):
  42. await websocket.accept()
  43. while True:
  44. data = await websocket.receive_text()
  45. await websocket.send_text(f"接收到的消息是:{data}")

사실 아주 간단합니다. 백엔드에서 메시지를 수신하기 위한 인터페이스를 작성합니다. 메시지가 오면 메시지를 처리합니다. 이전에는 http로 처리했지만 지금은 웹소켓입니다. 수신된 메시지를 프런트 엔드에 직접 반환했습니다.

효과를 살펴보겠습니다.

이런 식으로 우리는 웹소켓의 기능을 간단히 구현합니다. 그러면 구체적인 메시지가 있고 채팅을 종료합니다. 어떻게 처리해야 할까요?

  1. # 接收特定的消息后,终止该聊天
  2. @app.websocket("/ws")
  3. async def websocket_endpoint(websocket: WebSocket):
  4. await websocket.accept()
  5. while True:
  6. data = await websocket.receive_text()
  7. if data == "bye":
  8. await websocket.send_text(f"请注意:窗口即将关闭")
  9. await websocket.send_text("窗口已关闭")
  10. await websocket.close()
  11. break
  12. else:
  13. await websocket.send_text(f"接收到的消息是:{data}")

프론트엔드 코드는 변경되지 않았고, 백엔드만 수정되었습니다.

실제로 여기서 웹소켓 통신을 구현하는 것은 매우 간단합니다.

물론 요청에도 사용할 수 있습니다.

  • 달려있다
  • 보안
  • 쿠키
  • 머리글
  • 질문

간단한 백엔드 작성의 다음 예를 볼 수 있습니다.

  1. # 使用多种参数,比如获取cookie等
  2. from typing import Optional
  3. from fastapi import Cookie, Query, status, Depends
  4. async def get_cookie_or_token(
  5. websocket: WebSocket,
  6. session: Optional[str] = Cookie(None),
  7. token: Optional[str] = Query(None),
  8. ):
  9. if session is None and token is None:
  10. await websocket.close(code=status.WS_1008_POLICY_VIOLATION)
  11. return session or token
  12. @app.websocket("item/ws")
  13. async def websocket_endpoint(
  14. websocket: WebSocket,
  15. q: Optional[int] = None,
  16. cookie_or_token: str = Depends(get_cookie_or_token),
  17. ):
  18. await websocket.accept()
  19. while True:
  20. data = await websocket.receive_text()
  21. await websocket.send_text(
  22. f"Session cookie or query token value is: {cookie_or_token}"
  23. )
  24. if q is not None:
  25. await websocket.send_text(f"parameter q is: {q}")
  26. await websocket.send_text(f"Message text was: {data}, for : {q}")

단순히 백엔드를 구현했지만 fastapi가 websocket을 잘 지원한다는 것을 알 수 있습니다.