JS Socket 没有正确传递特殊字符

JS Socket not passing special characters correctly

所以,我经常看到这个问题,但公认的答案对我不起作用。我有一个我正在使用的类似聊天室的网站,虽然它在大多数情况下都运行良好(我知道我的代码还有其他一些小问题,但它们不是问题的一部分),我是每当涉及我的 JS 文件并且我使用套接字时,字符编码就会出现问题。我现在 post 我的 HTML 和 JS 文件:

HTML:

{% extends "layout.html" %}
{% block heading %}
    <meta charset="UTF-8">
    <script type="text/javascript" src="{{ url_for('static', filename='js/chatroom.js') }}"></script>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/chatroom.css') }}">
{% endblock %}
{% block body %}
    The Chatroom name is <span id="chatroom">{{ chatroom }}</span> and it's code is <span id="code">{{ code }}</span>
    <div id="messages">
    {% for message in messages %}
        {% if message.author == online_user %}
            <div class="own">{{ message.message }}</div>
        {% else %}
            <div class="other"><strong>{{ message.author }}</strong><br> {{ message.message }}</div>
        {% endif %}
    {% endfor %}
    </div>
    <textarea id="message" rows=5 cols=50></textarea>
    <input type="button" id="send" value="Send">
{% endblock %}

JS:

document.addEventListener('DOMContentLoaded', () => {
    var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port);
    socket.on('connect', () => {
        document.querySelector('#send').onclick = () => {
            const message = document.querySelector('#message').value;
            socket.emit('send message', {'chatroom': {'code':document.querySelector('#code').innerHTML, 'name': document.querySelector('#chatroom').innerHTML}, 'message': message});
        };
    });
    socket.on('broadcast message', data => {
        if (data.message['chatroom']['code'] == document.querySelector('#code').innerHTML) {
            const msg = document.createElement('div');
            if (data.message['author'] == document.getElementById('current_user').innerHTML)
                msg.innerHTML = data.message['message'];
            else
                msg.innerHTML = `${data.message['author']}: ${data.message['message']}`
            document.querySelector('#messages').append(msg);
            var listlen = document.getElementById('messages').getElementsByTagName('div').length;
            while (listlen > 100) {
                var msglist = document.getElementById('messages');
                msglist.removeChild(msglist.childNodes[0]);
                var listlen = document.getElementById('messages').getElementsByTagName('div').length;
            };
        };
    });
});

现在,当不涉及 JS 文件和套接字时(例如,如果我登录该站点),编码工作正常。但是,当 textarea 包含 Á 等特殊字符时(我将在两个字段中使用 Ángel 作为示例),一旦我点击发送按钮(不是之前),输出是错误的。

当前输出:{'chatroom': {'code': 'ouAY7mxCvhXb', 'name': 'UTF'}, 'author': 'Ángel', 'message': 'Ã\x81ngel'}

预期输出:{'chatroom': {'code': 'ouAY7mxCvhXb', 'name': 'UTF'}, 'author': 'Ángel', 'message': 'Ángel'}

标记此问题的其他问题的可接受答案是在我的 HTML 上添加 <meta charset="UTF-8"> 行,但我现在很困惑,因为它没有用。我也检查过,我的 JS 文件也正确编码为 UTF-8。

编辑:

我将为套接字添加服务器端代码,因为它可能有助于更好地理解输出。如此处所示,编码问题仅发生在我从 data 传递的内容中(仅在消息内容和聊天室名称上可能出错,因为聊天室代码是自动生成的,从不包含特殊字符)。

@socketio.on("send message")
def send_message(data):
    data['message'] = data['message'].strip()
    if len(data["message"]) > 0:
        message = {'chatroom': data['chatroom'], 'author': session['username'], 'message': data['message']}
        print(message)
        stored_messages.append(message)
        local_messages.append(message)
        emit("broadcast message", {'message': message}, broadcast=True)

如果有人遇到这个问题,我找到了解决方法,以备将来参考。我没有通过套接字传递原始消息并期望程序自动将其转换为带有元标记的 UTF-8,而是通过在 JS 文件上添加编码函数并将其应用于消息内容来对其进行编码。

    function encode_utf8(s) {
        return encodeURIComponent(s);
    }

JS 文件的第 4 行现在看起来像这样:const message = encode_utf8(document.querySelector('#message').value);

这允许我以我的后端服务器可以正确解码的方式发送它,因此它 returns 使用 urllib.parse 库的 unquote_plus.

的预期输出
@socketio.on("send message")
def send_message(data):
    data['message'] = data['message'].strip()
    print(data)
    if len(data["message"]) > 0:
        message = {'chatroom': data['chatroom'], 'author': session['username'], 'message': urllib.parse.unquote_plus(data['message'])} # <-- Modified line
        print(message)
        stored_messages.append(message)
        local_messages.append(message)
        emit("broadcast message", {'message': message}, broadcast=True)