Django channels not sending message on heroku live server

To send messages in real time, I have configured Django, channels, Redis, and Daphne. When it is being developed, it functions exactly as planned, but as soon as it is deployed to the live server, it stops functioning. The problem is that, contrary to my expectations, when I type a message in the input field and click the submit button, the page reloads. I’m not sure if the messages are actually transmitted or not when the page reloads, but because my database does not save the messages, I assume they are not.

I have preventDefault() in the javascript, or is there something else to do while on a live server?
This is the script that makes the call to the channels

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
    $(function () {
        var receiver = null;
        var receiver_id = "{{ reciever.username }}";
        var logged_in = "{{ request.user.username }}";
        const pathname = window.location.pathname;

        const parts = pathname.split("/");
        const username = parts[parts.length - 2];

        if (receiver_id === logged_in) {
            receiver = receiver_id;
        } else {
            receiver = receiver_id;
        }

        var socket = new WebSocket("ws://" + window.location.host + "/ws/chat/" + receiver + "/");

        socket.onopen = function () {
            console.log("WebSocket connection established.");
        };

        var typingTimer;
        var typingTimeout = 1000;

        $("#chat-input").on("input", function () {
            clearTimeout(typingTimer);

            typingTimer = setTimeout(function () {
                $("#typing-status").text("");
            }, typingTimeout);

            $("#typing-status").text("typing...");
        });

        socket.onmessage = function (event) {
            var data = JSON.parse(event.data);
            var message = data.message;
            var sender = data.sender;
            var profileImage = data.profile_image;
            var reciever = data.reciever;
            var typing = data.typing;

            if (sender === "{{sender}}") {
                var chatMessage = '<div class="d-flex flex-row justify-content-end message">';
                chatMessage += '<div style="margin-left: 20px;">';
                chatMessage += '<p class="small p-2 me-3 mb-1 text-white rounded-3 custom-bg">' + message + "</p>";
                chatMessage += '<p class="small me-3 mb-3 rounded-3 text-muted">0 minute ago</p>';
                chatMessage += "</div>";
                chatMessage += '<img style="width: 50px; height: 50px; object-fit: cover; border-radius: 50%; " src="' + profileImage + '" class="">';
                chatMessage += "</div>";
                $("#chat-messages").append(chatMessage);
                var chatContainer = document.querySelector(".chat_container");
                chatContainer.scrollTop = chatContainer.scrollHeight;
                console.log("Yes");
            } else {
                var chatMessage = '<div class="d-flex flex-row justify-content-start message">';
                chatMessage += '<img style="width: 50px; height: 50px; object-fit: cover; border-radius: 50%;" src="' + profileImage + '" class="">';
                chatMessage += '<div style=" padding-left: 13px;" >';
                chatMessage += '<p class="small p-2 me-3 mb-1 rounded-3" style="background-color: #f5f6f7;">' + message + "</p>";
                chatMessage += '<p class="small me-3 mb-3 rounded-3 text-muted">0 minute ago</p>';
                chatMessage += "</div>";
                chatMessage += "</div>";
                $("#chat-messages").append(chatMessage);
                var chatContainer = document.querySelector(".chat_container");
                chatContainer.scrollTop = chatContainer.scrollHeight;
                console.log("No");
            }

            if (typing && sender !== logged_in) {
                $("#typing-status").text("typing...");
            } else {
                $("#typing-status").text("");
            }
        };

        socket.onclose = function () {
            console.log("WebSocket connection closed.");
        };

        $("#chat-send").on("submit", function (e) {
            e.preventDefault();
            var input = $("#chat-input");
            var message = input.val();
            var sender = "{{request.user.username}}";
            var data = {
                message: message,
                sender: sender,
                reciever: username,
                typing: false,
            };
            socket.send(JSON.stringify(data));
            input.val("");
            var $proceedButton = $("#proceed-btn");
            $proceedButton.prop("disabled", true);
            $(".chat_container").scrollTop(100000000000);
            $("#message-form")[0].reset();
        });
    });

    $(document).ready(function () {
        $(".chat_container").scrollTop(100000000000);
        $("#message-form").preventDefault();
    });
</script>

Do I need to display more files, such as routing.py, settings.py, or consumer.py?

Your browser’s developer tools on the network tab is very useful for showing you the requests and responses. You can use it to see if you’re sending messages through the websocket or not.

In general, the situation you’re describing occurs when someone isn’t logged on when the websocket is being opened. (There are many reasons why this might be happening - that’s just one reason that I see frequently around here because people tend to open the websocket on the home page.)

I don’t know heroku, so unfortunately I’m not going to be able to provide you with any specific advice in that area, but I do notice a couple things you might want to think about changing.

First, there’s no need to define your button as a submit button. You can define it as a button and capture the click event for that button. That prevents the browser from even trying to submit the form as a regular post and avoids the need for calling preventDefault.

Second, these are apparently users that are logged on, which makes these lines in your JavaScript unnecessary:

and

The scope in the consumer contains the user associated with that socket, giving you a secure method of identifying the sender. (Your method doesn’t prevent someone from changing that variable and impersonating someone else.)

Along with the information above, this is very insecure:

You have absolutely no protection against impersonation here. These types of settings and protections should be handled by the server in the consumer. You want to become more familiar with the scope and the features available in the consumer.

Thank you very much for your response.

With the help of the developer tool, i found some errors that helped me fix the issues

This also stopped the page from reloading, and in the scripts, i had to change ws" to wss var socket = new WebSocket("ws://" ...") ; to var socket = new WebSocket("wss://" ...") ;

What I am still trying to figure out is how to prevent impersonation, just like you said. I’d really appreciate some guidance on how to do that, as right now I do not really know what to do about it.

When a person logs on before opening the websocket, the consumer creates the scope object which is available within the consumer. You don’t need to trust the browser to send in the current user, the consumer has it directly.

Now I understand, just to be sure: I can use scope["user"] on the consumer side if I configure authentication in the channel rather than doing let user = "{{ request.user }}" on the client side, am I right?

I don’t know what you mean by that.

My authentication occurs within Django, not Channels.

I don’t open the websocket until after the user has logged in.

At that point, Channels will have created the scope with the reference to the logged-in user.

If the websocket is opened before the user has logged in, then the scope can’t be created with a user.

Thanks a lot; using this, I have fixed the issue.