繁体   English   中英

如何在 Django 通道中获取 websocket 连接的客户端 IP 地址?

[英]How do I get the client IP address of a websocket connection in Django Channels?

我需要获取 websocket 连接的客户端 IP 地址,以实现我想要实现的一些额外功能。 我有一个现有部署的 Django 服务器运行 Nginx-Gunicorn-Uvicorn Worker-Redis 配置。 正如人们所预料的那样,在开发过程中,在运行本地服务器的同时,一切都按预期进行。 但是,在部署时,当我尝试通过self.scope["client"][0]访问 websocket 的客户端 IP 地址时,我收到错误NoneType object is not subscriptable

下面是配置和代码: NGINX Config:

upstream uvicorn {
    server unix:/run/gunicorn.sock;
}

server {
    listen 80;
    server_name <ip address> <hostname>;

    location = /favicon.ico { access_log off; log_not_found off; }

    location / {
        include proxy_params;
        proxy_set_header Connection "";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://uvicorn;
        proxy_headers_hash_max_size 512;
        proxy_headers_hash_bucket_size 128;
    }

    location /ws/ {
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_redirect off;
        proxy_pass http://uvicorn;
    }

    location /static/ {
        root /var/www/serverfiles/;
        autoindex off;
    }

    location /media {
        alias /mnt/apps;
    }
}

Gunicorn Config:注意:为了便于阅读,ExecStart 已被格式化,它是实际配置中的一行

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=django
Group=www-data
WorkingDirectory=/srv/server
Environment=DJANGO_SECRET_KEY=
Environment=GITEA_SECRET_KEY=
Environment=MSSQL_DATABASE_PASSWORD=
ExecStart=/bin/bash -c "
source venv/bin/activate;
exec /srv/server/venv/bin/gunicorn
    --workers 3
    --bind unix:/run/gunicorn.sock
    --timeout 300
    --error-logfile /var/log/gunicorn/error.log
    --access-logfile /var/log/gunicorn/access.log
    --log-level debug
    --capture-output
    -k uvicorn.workers.UvicornWorker
    src.server.asgi:application
"

[Install]
WantedBy=multi-user.target

代码抛出错误:

@database_sync_to_async
def _set_online_if_model(self, set_online: bool) -> None:
    model: MyModel
    for model in MyModel.objects.all():
        if self.scope["client"][0] == model.ip:
            model.online = set_online
            model.save()

在我需要访问连接客户端 IP 地址之前,该服务器在其当前配置下一直运行得非常好。 它可以很好地处理其他 websocket 连接,没有任何问题。

我已经研究过根据文档尝试配置我自己的自定义 UvicornWorker。 我根本不是这方面的专家,所以我可能误解了我应该做的事情: https://www.uvicorn.org/deployment/#running-behind-nginx

from uvicorn.workers import UvicornWorker


class ServerUvicornWorker(UvicornWorker):
    def __init__(self, *args, **kwargs) -> None:
        self.CONFIG_KWARGS.update({"proxy_headers": True, "forwarded_allow_ips": "*"})
        super().__init__(*args, **kwargs)

我还查看了https://github.com/django/channels/issues/546 ,其中提到了 Daphne 的--proxy-headers配置,但是,我没有运行 Daphne。 https://github.com/django/channels/issues/385提到 HTTP 标头被传递给消费者的connect方法,但是,该帖子很旧,据我所知不再相关。 我的连接方法没有得到任何额外的**kwargs

客户端IP 与频道无关

self.scope["client"][0] 未定义,因为当您在后端从前端接收数据时,没有名称为 client 的数据。 所以尝试从前端发送它。 可以先发一份手册,static的值先验证一下,然后找技术读取IP地址再发。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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