简体   繁体   中英

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. I have an existing deployed Django server running an Nginx-Gunicorn-Uvicorn Worker-Redis configuration. 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] .

Here are the configurations and code: 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

[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. It handles other websocket connections just fine without any issues.

I've already looked into trying to configure my own custom UvicornWorker according to the docs. 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

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/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. I do not get any additional **kwargs to my connect method.

Client IP has nothing to do with channels

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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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