简体   繁体   中英

How do I communicate with a websocket within a Django API GET request?

I'm trying to get a response from a websocket server (implemented with websockets and asyncio ) from within a Django REST API method. Something of the following structure:

Django App

(This does not work, but illustrates the idea)

class AnAPI(views.APIView):

    async def get(self, request):
        try:
            timeout = 5
            try:
                ws_conn = await asyncio.wait_for(websockets.connect(WS_STRING), timeout)
            except ConnectionTimeoutError as e:
                 <.....>

            await ws_conn.send(...)
            response = await ws_conn.recv()
            ws_conn.close()
            return Response(...)
        except Exception as e:
            print(e)
            return Response(...)

WS Server

ws_server = websockets.serve(...)
asyncio.get_event_loop().run_until_complete(ws_server)
asyncio.get_event_loop().run_forever()

Apparently, this makes the Django GET method return a <class 'coroutine'>

AssertionError: Expected a `Response`, `HttpResponse` or `HttpStreamingResponse` to be returned from the view, but received a `<class 'coroutine'>`

Any pointers would be much appreciated!


EDIT: Thanks to all of those who have answered. I was looking for a light weight solution as this is probably the only place where the Django app needed to interact with the WS server, I ended up adopting @Joran's solution, but packed everything into a helper function: something like this:

class AnAPI(views.APIView):

    def get(self, request):
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        result = loop.run_until_complete(my_async_helper_function())
        return Response(...)


async def my_async_helper_function():

    try:
            timeout = 5
            try:
                ws_conn = await asyncio.wait_for(websockets.connect(WS_STRING), timeout)
            except ConnectionTimeoutError as e:
                 <.....>

            await ws_conn.send(...)
            response = await ws_conn.recv()
            await ws_conn.close()
            return ...
        except Exception as e:
            print(e)
            await ws_conn.close()
            return ...


you cannot use async with django responses (I think...)

instead you could try

import asyncio

class AnAPI(views.APIView):
    def get(self, request):
        try:
        timeout = 5
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop) 
        try:                
            ws_conn = loop.run_until_complete(websockets.connect(WS_STRING), timeout)               
        except ConnectionTimeoutError as e:
             <.....>

        loop.run_until_complete(ws_conn.send(...))
        response = loop.run_until_complete(ws_conn.recv())
        ws_conn.close()
        return Response(...)

alternatively I believe https://pypi.org/project/websocket_client/ offers a non async interface which is very easy to use

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM