I am trying to deploy my app to heroku. The app has a simple chatting system that uses Websockets and django channels.
When I test my app using python manage.py runserver the app behaves just as intended.
I tried deploying the app and all features work except for the chatting system.
Here is the error message I am getting in the Chrome Console:
layout.js:108 Mixed Content: The page at 'https://desolate-lowlands-74512.herokuapp.com/index' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://desolate-lowlands-74512.herokuapp.com/ws/chat/19/'. This request has been blocked; this endpoint must be available over WSS.
This is what I tried to fix it: I went from ws to wss I changed this:
const chatSocket = new WebSocket('ws://'+ window.location.host+ '/ws/chat/'+ friendship_id+ '/');console.log(chatSocket)
to this:
const chatSocket = new WebSocket('wss://'+ window.location.host+ '/ws/chat/'+ friendship_id+ '/');console.log(chatSocket)
with this change the websocket loads but the chatting system still doesn't work. The messages still don't get sent or received
This is the error message I get when opening the Chatbox:
layout.js:108 WebSocket connection to 'wss://desolate-lowlands-74512.herokuapp.com/ws/chat/19/' failed: Error during WebSocket handshake: Unexpected response code: 404
and this is the error message I get when I try to send the message:
WebSocket is already in CLOSING or CLOSED state.
Here is the code: This is my asgi.py file:
"""
ASGI config for DBSF project.It exposes the ASGI callable as a module-level variable named ``application``.For more information on this file, see
https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/
"""import osfrom django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
import social.routingos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'DBSF.settings')application = ProtocolTypeRouter({"http": get_asgi_application(),"websocket": AuthMiddlewareStack(URLRouter(social.routing.websocket_urlpatterns)),
})
here is routing.py
from django.urls import re_path
from . import consumerswebsocket_urlpatterns = [re_path(r'ws/chat/(?P<friendship_id>\w+)/$', consumers.ChatConsumer.as_asgi()),
]
Here's consumers.py
import json
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
from .models import Message, Friendship, User
import datetimeclass ChatConsumer(WebsocketConsumer):def connect(self):self.room_name = self.scope['url_route']['kwargs']['friendship_id']self.room_group_name = 'chat_%s' % self.room_name# Join room groupasync_to_sync(self.channel_layer.group_add)(self.room_group_name,self.channel_name)self.accept()def disconnect(self, close_code):# Leave room groupasync_to_sync(self.channel_layer.group_discard)(self.room_group_name,self.channel_name)# Receive message from WebSocketdef receive(self, text_data):text_data_json = json.loads(text_data)message = text_data_json['message']sender = text_data_json['sender']receiver = text_data_json['receiver']friendship_id = self.scope['url_route']['kwargs']['friendship_id']message_to_save = Message(conversation=Friendship.objects.get(id=friendship_id), sender=User.objects.get(username=sender), receiver=User.objects.get(username=receiver), text=message, date_sent=datetime.datetime.now())message_to_save.save()# Send message to room groupasync_to_sync(self.channel_layer.group_send)(self.room_group_name,{'type': 'chat_message','message': message,'sender': sender,'receiver': receiver,'id': message_to_save.id})# Receive message from room groupdef chat_message(self, event):message = event['message']sender = event['sender']receiver = event['receiver']id = event['id']# Send message to WebSocketself.send(text_data=json.dumps({'message': message,'sender': sender,'receiver': receiver,'id': id,}))
Here is settings.py
"""
Django settings for DBSF project.Generated by 'django-admin startproject' using Django 3.1.2.For more information on this file, see
https://docs.djangoproject.com/en/3.1/topics/settings/For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.1/ref/settings/
"""from pathlib import Path
import django_heroku
import os
from dotenv import load_dotenv
load_dotenv()
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ['SECRET_KEY']
AUTH_USER_MODEL = 'social.User'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['desolate-lowlands-74512.herokuapp.com', 'localhost', '127.0.0.1']# Application definitionINSTALLED_APPS = ['channels','social','django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles',
]MIDDLEWARE = ['django.middleware.security.SecurityMiddleware','whitenoise.middleware.WhiteNoiseMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',
]ROOT_URLCONF = 'DBSF.urls'TEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates','DIRS': [],'APP_DIRS': True,'OPTIONS': {'context_processors': ['django.template.context_processors.debug','django.template.context_processors.request','django.contrib.auth.context_processors.auth','django.contrib.messages.context_processors.messages',],},},
]REST_FRAMEWORK = {# Use Django's standard `django.contrib.auth` permissions,# or allow read-only access for unauthenticated users.'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly']
}WSGI_APPLICATION = 'DBSF.wsgi.application'
ASGI_APPLICATION = 'DBSF.asgi.application'
CHANNEL_LAYERS = {'default': {'BACKEND': 'channels_redis.core.RedisChannelLayer','CONFIG': {"hosts": [('127.0.0.1', 6379)],},},
}# Database
# https://docs.djangoproject.com/en/3.1/ref/settings/#databasesDATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3','NAME': BASE_DIR / 'db.sqlite3',}
}# Password validation
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validatorsAUTH_PASSWORD_VALIDATORS = [{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',},{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',},{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',},{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',},
]# Internationalization
# https://docs.djangoproject.com/en/3.1/topics/i18n/LANGUAGE_CODE = 'en-us'TIME_ZONE = 'EST'USE_I18N = TrueUSE_L10N = TrueUSE_TZ = True# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'
MEDIA_ROOT= os.path.join(BASE_DIR, 'media/')
MEDIA_URL= "/media/"
here's wsgi.py
"""
WSGI config for DBSF project.It exposes the WSGI callable as a module-level variable named ``application``.For more information on this file, see
https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/
"""import osfrom django.core.wsgi import get_wsgi_applicationos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'DBSF.settings')application = get_wsgi_application()
I assume the once I change from ws to wss the consumer can't connect. I think this will be an easy fix but I can't figure out what code i need to change. I suspect that it is something in asgy.py or routing.py
Please let me know if it is unclear what I am asking or if I need to show any other files