question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[BUG] Tutorial websocket doc example

See original GitHub issue

Describe the bug Hi, On the docs of websocket the last example doesn’t work.

To Reproduce Steps to reproduce the behavior:

  1. Create a file main.py with the last example on the bottom of the file

https://fastapi.tiangolo.com/tutorial/websockets/#create-a-websocket

from fastapi import Cookie, Depends, FastAPI, Header
from starlette.responses import HTMLResponse
from starlette.status import WS_1008_POLICY_VIOLATION
from starlette.websockets import WebSocket

app = FastAPI()

html = """
<!DOCTYPE html>
<html>
    <head>
        <title>Chat</title>
    </head>
    <body>
        <h1>WebSocket Chat</h1>
        <form action="" onsubmit="sendMessage(event)">
            <label>Item ID: <input type="text" id="itemId" autocomplete="off" value="foo"/></label>
            <button onclick="connect(event)">Connect</button>
            <br>
            <label>Message: <input type="text" id="messageText" autocomplete="off"/></label>
            <button>Send</button>
        </form>
        <ul id='messages'>
        </ul>
        <script>
        var ws = null;
            function connect(event) {
                var input = document.getElementById("itemId")
                ws = new WebSocket("ws://localhost:8000/items/" + input.value + "/ws");
                ws.onmessage = function(event) {
                    var messages = document.getElementById('messages')
                    var message = document.createElement('li')
                    var content = document.createTextNode(event.data)
                    message.appendChild(content)
                    messages.appendChild(message)
                };
            }
            function sendMessage(event) {
                var input = document.getElementById("messageText")
                ws.send(input.value)
                input.value = ''
                event.preventDefault()
            }
        </script>
    </body>
</html>
"""


@app.get("/")
async def get():
    return HTMLResponse(html)


async def get_cookie_or_client(
    websocket: WebSocket, session: str = Cookie(None), x_client: str = Header(None)
):
    if session is None and x_client is None:
        await websocket.close(code=WS_1008_POLICY_VIOLATION)
    return session or x_client


@app.websocket("/items/{item_id}/ws")
async def websocket_endpoint(
    websocket: WebSocket,
    item_id: int,
    q: str = None,
    cookie_or_client: str = Depends(get_cookie_or_client),
):
    await websocket.accept()
    while True:
        data = await websocket.receive_text()
        await websocket.send_text(
            f"Session Cookie or X-Client Header value is: {cookie_or_client}"
        )
        if q is not None:
            await websocket.send_text(f"Query parameter q is: {q}")
        await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}")
  1. Run the application with the cmd:
uvicorn main:app  --log-level debug --reload
  1. Open the browser 127.0.0.01
  • the first time i connect with ItemID foo , press the button connect
  • send message hi with ItemID foo and press the button send. it’s look like the connect fail but the second ,but the send have return code 200 but nothing happen on the web side.

image

  1. See error

INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [366952]
email-validator not installed, email fields will be treated as str.
To install, run: pip install email-validator
INFO: Started server process [366957]
INFO: Waiting for application startup.
DEBUG: None - ASGI [1] Started
DEBUG: None - ASGI [1] Sent {'type': 'lifespan.startup'}
DEBUG: None - ASGI [1] Received {'type': 'lifespan.startup.complete'}
DEBUG: ('127.0.0.1', 50056) - Connected
DEBUG: server - state = CONNECTING
DEBUG: server - event = connection_made(<TCPTransport closed=False reading=True 0x1819178>)
DEBUG: ('127.0.0.1', 50056) - ASGI [2] Started
DEBUG: ('127.0.0.1', 50056) - ASGI [2] Received {'type': 'websocket.close', 'code': 1008}
INFO: ('127.0.0.1', 50056) - "WebSocket /items/foo/ws" 403
DEBUG: ('127.0.0.1', 50056) - ASGI [2] Raised exception
ERROR: Exception in ASGI application
Traceback (most recent call last):
  File "/data/experiments/realtime_web_socket/lib/python3.7/site-packages/uvicorn/protocols/websockets/websockets_impl.py", line 147, in run_asgi
    result = await self.app(self.scope, self.asgi_receive, self.asgi_send)
  File "/data/experiments/realtime_web_socket/lib/python3.7/site-packages/uvicorn/middleware/message_logger.py", line 58, in __call__
    raise exc from None
  File "/data/experiments/realtime_web_socket/lib/python3.7/site-packages/uvicorn/middleware/message_logger.py", line 54, in __call__
    await self.app(scope, inner_receive, inner_send)
  File "/data/experiments/realtime_web_socket/lib/python3.7/site-packages/starlette/applications.py", line 133, in __call__
    await self.error_middleware(scope, receive, send)
  File "/data/experiments/realtime_web_socket/lib/python3.7/site-packages/starlette/middleware/errors.py", line 87, in __call__
    await self.app(scope, receive, send)
  File "/data/experiments/realtime_web_socket/lib/python3.7/site-packages/starlette/exceptions.py", line 49, in __call__
    await self.app(scope, receive, send)
  File "/data/experiments/realtime_web_socket/lib/python3.7/site-packages/starlette/routing.py", line 585, in __call__
    await route(scope, receive, send)
  File "/data/experiments/realtime_web_socket/lib/python3.7/site-packages/starlette/routing.py", line 265, in __call__
    await self.app(scope, receive, send)
  File "/data/experiments/realtime_web_socket/lib/python3.7/site-packages/starlette/routing.py", line 56, in app
    await func(session)
  File "/data/experiments/realtime_web_socket/lib/python3.7/site-packages/fastapi/routing.py", line 148, in app
    await websocket.close(code=WS_1008_POLICY_VIOLATION)
  File "/data/experiments/realtime_web_socket/lib/python3.7/site-packages/starlette/websockets.py", line 121, in close
    await self.send({"type": "websocket.close", "code": code})
  File "/data/experiments/realtime_web_socket/lib/python3.7/site-packages/starlette/websockets.py", line 70, in send
    raise RuntimeError('Cannot call "send" once a close message has been sent.')
RuntimeError: Cannot call "send" once a close message has been sent.
DEBUG: server ! failing WebSocket connection in the CONNECTING state: 1006 [no reason]
DEBUG: ('127.0.0.1', 50058) - Connected
DEBUG: server x half-closing TCP connection
DEBUG: ('127.0.0.1', 50058) - ASGI [3] Started
DEBUG: ('127.0.0.1', 50058) - ASGI [3] Received {'type': 'http.response.start', 'status': 200, 'headers': '<...>'}
INFO: ('127.0.0.1', 50058) - "GET / HTTP/1.1" 200
DEBUG: ('127.0.0.1', 50058) - ASGI [3] Received {'type': 'http.response.body', 'body': '<1419 bytes>'}
DEBUG: ('127.0.0.1', 50058) - ASGI [3] Completed
DEBUG: server - event = eof_received()
DEBUG: server - event = connection_lost(None)
DEBUG: server - state = CLOSED
DEBUG: server x code = 1006, reason = [no reason]
DEBUG: ('127.0.0.1', 50058) - Disconnected
DEBUG: ('127.0.0.1', 50060) - Connected
DEBUG: ('127.0.0.1', 50060) - ASGI [4] Started
DEBUG: ('127.0.0.1', 50060) - ASGI [4] Received {'type': 'http.response.start', 'status': 200, 'headers': '<...>'}
INFO: ('127.0.0.1', 50060) - "GET / HTTP/1.1" 200
DEBUG: ('127.0.0.1', 50060) - ASGI [4] Received {'type': 'http.response.body', 'body': '<1419 bytes>'}
DEBUG: ('127.0.0.1', 50060) - ASGI [4] Completed
DEBUG: ('127.0.0.1', 50060) - Disconnected


Expected behavior expected to appear the send bold message on the web page.

Environment:

  • OS: centos 7
  • FastAPI Version [e.g. 0.3.0], get it with: fastapi==0.31.0
import fastapi
print(fastapi.__version__)
0.31.0
  • Python version, get it with:
python --version
Python 3.7.3

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:15 (3 by maintainers)

github_iconTop GitHub Comments

4reactions
tiangolocommented, Jun 13, 2020

Thanks for the discussion here everyone! ☕

It was updated and simplified as part of https://github.com/tiangolo/fastapi/pull/1540

You can check the new docs here: https://fastapi.tiangolo.com/advanced/websockets/#using-depends-and-others 🚀

I’m re-opening the issue to give time for the author of the issue to confirm and close it 🤓

4reactions
alj06kacommented, Jul 5, 2019

@BenjPy , Just add event.preventDefault() in the beginning of connect js function. The problem here is when you are trying to make websocket connection, browser refreshes page and closes websocket connection. So connect function should looks like this:

function connect(event) {
    event.preventDefault()
    var input = document.getElementById("itemId")
    ws = new WebSocket("ws://localhost:8000/items/" + input.value + "/ws");
    ws.onmessage = function(event) {
        var messages = document.getElementById('messages')
        var message = document.createElement('li')
        var content = document.createTextNode(event.data)
        message.appendChild(content)
        messages.appendChild(message)
    };
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Writing WebSocket client applications - Web APIs | MDN
This simple example creates a new WebSocket, connecting to the server at wss://www.example.com/socketserver . A custom protocol of "protocolOne" ...
Read more >
Part 1 - Send & receive - websockets 10.4 documentation
In this tutorial, you're going to build a web-based Connect Four game. The web removes the constraint of being in the same room...
Read more >
WebSocket - The Modern JavaScript Tutorial
A simple example ; open – connection established, ; message – data received, ; error – websocket error, ; close – connection closed....
Read more >
Building a Complete WebSocket App From Scratch ... - YouTube
Today you're gonna implement the Web Socket protocol from scratch using only Node.js and JavaScript. You'll get to know what are bitwise ...
Read more >
Websockets Tutorial Creating a real-time Websocket Server
socket.onmessage - any time the server sends a message to us, this fires. In our example, we will append a new element to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found