简体   繁体   English

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

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

I need to get the client IP address of a websocket connection for some extra functionality I would like to implement.我需要获取 websocket 连接的客户端 IP 地址,以实现我想要实现的一些额外功能。 I have an existing deployed Django server running an Nginx-Gunicorn-Uvicorn Worker-Redis configuration.我有一个现有部署的 Django 服务器运行 Nginx-Gunicorn-Uvicorn Worker-Redis 配置。 As one might expect, during development, whilst running a local server, everything works as expected.正如人们所预料的那样,在开发过程中,在运行本地服务器的同时,一切都按预期进行。 However, when deployed, I receive the error NoneType object is not subscriptable when attempting to access the client IP address of the websocket via self.scope["client"][0] .但是,在部署时,当我尝试通过self.scope["client"][0]访问 websocket 的客户端 IP 地址时,我收到错误NoneType object is not subscriptable

Here are the configurations and code: NGINX Config:下面是配置和代码: 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: NOTE: ExecStart has been formatted for readability, it is one line in the actual config 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

Code throwing the error:代码抛出错误:

@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()

This server has been running phenomenally in its current configuration before my need to access connect client IP addresses.在我需要访问连接客户端 IP 地址之前,该服务器在其当前配置下一直运行得非常好。 It handles other websocket connections just fine without any issues.它可以很好地处理其他 websocket 连接,没有任何问题。

I've already looked into trying to configure my own custom UvicornWorker according to the docs.我已经研究过根据文档尝试配置我自己的自定义 UvicornWorker。 I'm not at all an expert in this, so I might have misunderstood what I was supposed to do: https://www.uvicorn.org/deployment/#running-behind-nginx我根本不是这方面的专家,所以我可能误解了我应该做的事情: 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)

I also looked at https://github.com/django/channels/issues/546 which mentioned a --proxy-headers config for Daphne, however, I am not running Daphne.我还查看了https://github.com/django/channels/issues/546 ,其中提到了 Daphne 的--proxy-headers配置,但是,我没有运行 Daphne。 https://github.com/django/channels/issues/385 mentioned that HTTP headers are passed to the connect method of a consumer, however, that post is quite old and no longer relavent as far as I can tell. https://github.com/django/channels/issues/385提到 HTTP 标头被传递给消费者的connect方法,但是,该帖子很旧,据我所知不再相关。 I do not get any additional **kwargs to my connect method.我的连接方法没有得到任何额外的**kwargs

Client IP has nothing to do with channels客户端IP 与频道无关

self.scope["client"][0] is undefined because when you receive data from the front end at the backend there is no data with the name client. self.scope["client"][0] 未定义,因为当您在后端从前端接收数据时,没有名称为 client 的数据。 so try to send it from the frontend.所以尝试从前端发送它。 you can send a manual, static value at first to verify and then find techniques to read the IP address and then send it.可以先发一份手册,static的值先验证一下,然后找技术读取IP地址再发。

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

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