Websocket connection failed: Error during WebSocket handshake: Unexpected response code: 200

2,178 views
Skip to first unread message

flora.xia...@gmail.com

unread,
Jun 24, 2018, 9:29:25 PM6/24/18
to Django users
Hi I am deploying a website with a live discussion feature. But people cannot send nor receive messages on this discussion page. In the console it shows: "WebSocket connection to 'ws://xxxxxxxx/room1/' failed: Error during WebSocket handshake: Unexpected response code: 200"

I don't know where the websocket bug (or bugs from other sources) is. I am attaching some information that I think might be helpful. Could someone help? If you think I miss some information please let me know and I will post! Thanks!!!!!!


Server: ubuntu 14.03
nginx
commands to start the website:
     uwsgi --socket experiment_platform.sock --module experiment_platform.wsgi --chmod-socket=666 --processes=6
daphne experiment_platform.asgi:channel_layer --port 8000 --bind 0.0.0.0 -v2 &
python manage.py runworker -v2 &
[redis server is also activated.]

log information of uwsgi (it keeps updating similar things after the discussion page is opened, whether or not I am trying to send messages to test or not. I think it's trying to establish the websocket connection.)
[pid: 29881|app: 0|req: 33/143] 100.15.133.125 () {52 vars in 1094 bytes} [Mon Jun 25 01:23:59 2018] GET /forum/room1/ => generated 4792 bytes in 55 msecs (HTTP/1.1 200) 3 headers in 102 bytes (1 switches on core 0) [pid: 29885|app: 0|req: 29/144] 100.15.133.125 () {52 vars in 1094 bytes} [Mon Jun 25 01:24:29 2018] GET /forum/room1/ => generated 4792 bytes in 57 msecs (HTTP/1.1 200) 3 headers in 102 bytes (1 switches on core 0)

log information of runworker (it doesn't update after opening the discussion page.)
2018-06-25 00:22:42,827 - INFO - runworker - Running worker against channel layer default (asgi_redis.core.RedisChannelLayer)
2018-06-25 00:22:42,828 - INFO - worker - Listening on channels http.request, websocket.connect, websocket.disconnect, websocket.receive

forum/consumers.py
import re import json import logging from channels import Group from channels.sessions import channel_session from .models import Discussion, Statement, Vote from chat.models import Room from experiment.models import ExpUser,TaskUser, Crowd from channels.auth import http_session, http_session_user, channel_session_user, channel_session_user_from_http log = logging.getLogger(__name__) @channel_session_user_from_http @channel_session def ws_connect(message): # Extract the discussion-label from the message. This expects message.path to be of the # form forum/{label}/, and finds a Discussion if the message path is applicable, # and if the Discussion exists. Otherwise, bails (meaning this is a some othersort # of websocket). So, this is effectively a version of _get_object_or_404. try: log.debug('In the try block of ws_connect')#added by me prefix, label = message['path'].decode('ascii').strip('/').split('/') if prefix != 'forum': log.debug('invalid ws path=%s', message['path']) return if prefix == 'forum': discussion = Discussion.objects.get(label=label) except ValueError: log.debug('invalid ws path=%s', message['path']) return except Discussion.DoesNotExist: log.debug('ws discussion does not exist label=%s', label) return if prefix == 'forum': log.debug('forum connect discussion=%s client=%s:%s', discussion.label, message['client'][0], message['client'][1]) t = TaskUser(user=message.user,crowd=label,time_type='start') t.save() # Need to be explicit about the channel layer so that testability works # This may be a FIXME? Group('forum-'+label, channel_layer=message.channel_layer).add(message.reply_channel) message.channel_session['discussion'] = discussion.label message.reply_channel.send({ 'accept': True }) @channel_session_user @channel_session def ws_receive(message): if 'discussion' in message.channel_session: # Look up the room from the channel session, bailing if it doesn't exist try: label = message.channel_session['discussion'] discussion = Discussion.objects.get(label=label) except KeyError: log.debug('no discussion-forum in channel_session') return except Discussion.DoesNotExist: log.debug('recieved message, buy discussion does not exist label=%s', label) return try: expuser = ExpUser.objects.get(user=message.user) except KeyError: log.debug('problem getting username') return except ExpUser.DoesNotExist: log.debug('recieved message, but user does not exist label=%s', label) return # Parse out a chat message from the content text, bailing if it doesn't # conform to the expected message format. try: data = json.loads(message['text']) except ValueError: log.debug("ws message isn't json text=%s", text) return if data: if data['msg_type'] == 'vote': log.debug('vote handle=%s value=%s', expuser.nickname, data['value']) statement = Statement.objects.get(id=data['id']) m0 = statement.as_dict() log.debug('vote id=%s, score=%s, ups=%s, downs=%s',statement.id,statement.score,statement.ups,statement.downs) ndata = {'user':message.user,'handle':expuser.nickname,'statement':statement,'value':data['value']} vote = None votes = Vote.objects.filter(user=message.user,statement=statement) if not votes: vote = Vote.objects.create(**ndata) else: vote = votes[0] vote.value = data['value'] vote.save() m = statement.update_score() m['msg_type'] = 'vote' log.debug('vote score=%s', m['score']) # See above for the note about Group Group('forum-'+label, channel_layer=message.channel_layer).send({'text': json.dumps(m)}) else: log.debug('chat message handle=%s message=%s', expuser.nickname, data['message']) parent = None log.debug(data['parentid']) if data['parentid']!=0: parent = discussion.statements.get(id=data['parentid']) log.debug(parent.id) data['parent'] = parent data.pop("msg_type",None) data['user'] = message.user data['handle'] = expuser.nickname data['crowd_label'] = discussion.crowd_label data['task_label'] = discussion.task_label m = discussion.statements.create(**data) # NEED TO FIX HERE # See above for the note about Group Group('forum-'+label, channel_layer=message.channel_layer).send({'text': json.dumps(m.as_dict())}) @channel_session_user @channel_session def ws_disconnect(message): if 'discussion' in message.channel_session: try: label = message.channel_session['discussion'] discussion = Discussion.objects.get(label=label) t = TaskUser(user=message.user,crowd=label,time_type='end') t.save() Group('forum-'+label, channel_layer=message.channel_layer).discard(message.reply_channel) except (KeyError, Discussion.DoesNotExist): pass

settings.py
CHANNEL_LAYERS = { "default": { "BACKEND": "asgi_redis.RedisChannelLayer", "CONFIG": { "hosts": [os.environ.get('REDISTOGO_URL', 'redis://localhost:6379')], }, "ROUTING": "experiment_platform.routing.channel_routing", #"ROUTING": "waiting_room.routing.channel_routing", }, } CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://localhost:6379/1", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", } } }

赖信桃

unread,
Jun 25, 2018, 8:36:10 AM6/25/18
to django...@googlegroups.com
I haven't use Django's channel yet, but I guess that you route your url in a wrong way. Somehow your websocket connection goes to your uWSGI server, it should goes to your daphne server.

Did your daphne receive any connection request?

And you shouldn't use this on server:

python manage.py runworker -v2 &

It's for development use, I think. In your server you use uWSGI as HTTP server and daphne as websocket server.

<flora.xia...@gmail.com>于2018年6月25日周一 上午9:29写道:
--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/f2bcc2be-7bf6-4947-b396-cc4feb44894b%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Mikhailo Keda

unread,
Jun 25, 2018, 10:55:37 AM6/25/18
to Django users
probably you added this path /forum/room1/ to urls.py, you need to add this path to routing https://channels.readthedocs.io/en/latest/topics/routing.html

flora.xia...@gmail.com

unread,
Jun 25, 2018, 11:18:38 AM6/25/18
to Django users
Thanks for your reply. 

Here is the log information of daphne:
     2018-06-25 15:12:38,199 INFO     Starting server at tcp:port=8000:interface=0.0.0.0, channel layer experiment_platform.asgi:channel_layer.
     2018-06-25 15:12:38,200 INFO     HTTP/2 support not enabled (install the http2 and tls Twisted extras)
     2018-06-25 15:12:38,200 INFO     Using busy-loop synchronous mode on channel layer
     2018-06-25 15:12:38,201 INFO     Listening on endpoint tcp:port=8000:interface=0.0.0.0
     2018-06-25 15:12:38,201 INFO     HTTPFactory starting on 8000
     2018-06-25 15:12:38,202 INFO     Starting factory <daphne.http_protocol.HTTPFactory instance at 0x7f1a36681560
And it doesn't update after I do test on the website.

I thought runserver is for development and runworker is for production. Am I misunderstanding?...

flora.xia...@gmail.com

unread,
Jun 25, 2018, 11:21:34 AM6/25/18
to Django users
Thanks for your reply. But I am afraid this is not the problem. The urls are dispatched correctly. Different pages of my website can be directed correctly. 
The live discussion is just one function on one page. Other parts of this page are functioning well. 

赖信桃

unread,
Jun 25, 2018, 11:36:00 AM6/25/18
to django...@googlegroups.com
No, runserver is for web development, and runworker is for channel (AKA websocket) development.

And in production, you need uWSGI for runserver and daphne for runworker.

<flora.xia...@gmail.com>于2018年6月25日周一 下午11:21写道:
--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.

flora.xia...@gmail.com

unread,
Jun 25, 2018, 11:46:51 AM6/25/18
to Django users
So you mean I need these two commands to get my website running. Do you notice something unusual from the log info of uwsgi and daphne?

Mikhailo Keda

unread,
Jun 25, 2018, 11:55:01 AM6/25/18
to Django users
no, for Channels 2 you need one command

flora.xia...@gmail.com

unread,
Jun 25, 2018, 12:09:39 PM6/25/18
to Django users
Are you referring to only using daphne command? I cannot get my website running with only this command.

Mikhailo Keda

unread,
Jun 25, 2018, 12:35:58 PM6/25/18
to Django users
yea, why not?

I'm using daphne with supervisord + Nginx

flora.xia...@gmail.com

unread,
Jun 25, 2018, 2:53:57 PM6/25/18
to Django users
Oh... I'd better not change the framework of my website. Do you have any ideas about the bug based on the existing information I provide?

flora.xia...@gmail.com

unread,
Jun 26, 2018, 10:09:05 PM6/26/18
to Django users
I think I must have messed the ports up. Here is a summary:
     redis: 6379
daphne: 8000 (if running daphne with this command: daphne experiment_platform.asgi:channel_layer --port 8000 --bind 0.0.0.0 -v2 &)
ws (see nginx.conf): 8000 [I guess the error message in the browser console "WebSocket connection to 'ws://xxxxxxxx/room1/' failed: Error during WebSocket handshake: Unexpected response code: 200" means that I did make a mistake in this nginx.conf, right?]

Thanks.

It occurs to me that posting the nginx.conf might be helpful:
upstream django {
    server unix://myproject/experiment_platform.sock;
}
server{
    listen 80;
    server_name myproject;
    charset utf-8;
    client_max_body_size 20M;

    location /static {
        alias myproject/static;
    }

    location / {
        include myproject/uwsgi_params;
        uwsgi_pass unix://myproject/experiment_platform.sock;
    }
    location /ws {
        proxy_pass http://0.0.0.0:8000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_redirect     off;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Host $server_name;
    }
}

赖信桃

unread,
Jun 26, 2018, 10:48:16 PM6/26/18
to django...@googlegroups.com
Again, websocket is different from HTTP, both are built on TCP. So Nginx preoxy_pass is for HTTP forward, so you can not use it for HTTP for tanspond.

Maybe remove location /ws would work. Just use daphne as ws server.


<flora.xia...@gmail.com>于2018年6月27日周三 上午10:09写道:
--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.

Xiaoyun Huang

unread,
Jun 26, 2018, 11:02:12 PM6/26/18
to django...@googlegroups.com
Thanks for your information!

I just did all the configurations again following this post(http://masnun.rocks/2016/11/02/deploying-django-channels-using-daphne/). And I think it is extremely useful for me and my website is now running. And you are right, I don't need both uwsgi and daphne. Only daphne is sufficient.

<flora.xia...@gmail.com>于2018年6月27日周三 上午10:09写道:
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.

--
You received this message because you are subscribed to a topic in the Google Groups "Django users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-users/2ZOQY_rj6KM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-users+unsubscribe@googlegroups.com.

To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.

Mikhailo Keda

unread,
Jun 27, 2018, 12:30:47 AM6/27/18
to Django users

That post is outdated (it's not for Chanels 2), you nginx.conf is wrong, ws isn't location, it's protocol so you web sockets connections are forwarded to unix://myproject/experiment_platform.sock; and this triggers your error

You just need forward all connections to daphne (except /static)
Reply all
Reply to author
Forward
0 new messages