Docker nginx websocket proxy ==客户端在等待请求时关闭连接

时间:2018-02-10 19:59:55

标签: docker nginx websocket

我拼命尝试将nginx代理设置为websocket。 Websocket连接,但后来我

  

2018/02/10 19:30:34 [info] 7#7:* 238客户端关闭连接时   等待请求,客户端:172.18.0.1,服务器:0.0.0.0:8888

这是最小的例子:

nginx.conf

worker_processes  1;

events {
    worker_connections  1024;
}
error_log /dev/stdout debug;

http  {
    resolver 127.0.0.11 ipv6=off;
    include       mime.types;
    access_log /dev/stdout;
    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    upstream tornado {
      server ws:8888;
      #server ws:8889; I may add another upstream here
    }

    server {
         add_header X-Frame-Options SAMEORIGIN;
         add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";

        listen 8888;

        server_name pychat.org;
        charset     utf-8;
        client_max_body_size 75M;

        location / {
             proxy_pass http://tornado/;
             #>>> otherwise error 400
             proxy_set_header Upgrade $http_upgrade;
             proxy_set_header Connection "upgrade";
             proxy_set_header Host $host;
             proxy_send_timeout 330;
             proxy_read_timeout 330;
             #>>>>>>
             #proxy_redirect off;
             proxy_set_header X-Real-IP $remote_addr;
             #proxy_set_header X-Scheme $scheme;
        }

    }
}

server.py

import tornado.ioloop
from tornado.websocket import WebSocketHandler, WebSocketClosedError
from tornado import web
class MainHandler(WebSocketHandler):

    def open(self):
        print("WebSocket opened")

    def on_message(self, message):
        print("ws mess" +  message)
        self.write_message(u"You said: " + message)

    def on_close(self):
        print("WebSocket closed")

    def check_origin(self, origin):
        return True

def make_app():
    return tornado.web.Application([
        (r'.*', MainHandler),
    ])

if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()

搬运工-compose.yml

version: '2.3'
services:
  nginx:
    build:
      context: ../
      dockerfile: ./dockerfilenginx
    ports:
     - 8888:8888
  ws:
    build:
      context: ../
      dockerfile: ./docker/Dockerfilews

Dockerfilenginx

FROM alpine:3.6
RUN apk update &&\
apk add vim nginx ca-certificates wget && update-ca-certificates
COPY ./docker/nginx-test.conf /etc/nginx/nginx.conf
CMD ["nginx", "-g", "pid /tmp/nginx.pid; daemon off;"]

Dockerfilews

FROM alpine:3.6
RUN apk update &&\
 apk add python3 &&\
pip3 install tornado
WORKDIR /usr/src
COPY ./server.py /usr/src
CMD python3 server.py

然后尝试打开W​​ebSocket到服务器,例如从浏览器控制台(shift + ctrl + i)。

ws = new WebSocket('ws://localhost:8888')
ws.send("wsdata")

如果我删除nginx代理并在docker上公开websocket端口 - 一切都会正常工作。

2 个答案:

答案 0 :(得分:1)

你能为nginx尝试这个代理配置,我用它来代替django和daphne

proxy_http_version 1.1; 解决了这个问题。

location / {
    proxy_pass http://ws:8888;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    proxy_redirect     off;
    proxy_set_header   Host $host;
    proxy_set_header   X-Real-IP $remote_addr;
    proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header   X-Forwarded-Host $server_name;
}

答案 1 :(得分:0)

我也有这个问题,并认为它与Nginx有关,但这是一条红鲱鱼。

就我而言,我的代码在频道上发送消息时会定期引发异常。当我介绍了Nginx并关闭了“死”通道(AFAIK)时,这才变得显而易见。但是,这在我看来像是一个超时,因此我检查了代理超时和各种情况。

最终,我在代码中添加了更多日志记录,并意识到该错误实际上部分是由以下示例引起的:

async_to_sync(channel_layer.group_send)(
                        'notifications', {
                            "type": "notification",
                            "data": some_packet
                        }
                    )

我的消费者在收到此消息时期望有一个“文本”属性,但处理得不好。

然后关闭套接字,Nginx丢弃了它,我认为这是Nginx / Daphne / Docker-networking出现了2天的问题。

希望这对某人有帮助。