websocket使用nginx作为反向代理

需要nginx作为websocket的反向代理,没有nginx反向代理时候没有问题,通过nginx反向代理后会报400错误,查后台调试信息:

tornado.general – DEBUG – Can “Upgrade” only to “WebSocket”.

通过分析原来是需要nginx做如下配置:

upstream wsbackend {
server 127.0.0.1:10003;
}

server {
listen 3000;
server_name localhost;

#charset koi8-r;

#access_log logs/host.access.log main;

# location / {
# root html;
# index index.html index.htm;
# }

location / {
proxy_pass http://wsbackend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “upgrade”;
}
}

如果有多层反向代理的话需要在每一层都加上该信息!

WebSocket实验(实现跨域)

前端代码

<html>
<head>
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="viewport" content="initial-scale=1.0,maximum-scale=1.0">

    <script>

        var socket;

        if(typeof(WebSocket) == "undefined")
        {

            alert("您的浏览器不支持WebSocket");
        }
        //
var ws = new WebSocket('ws://ws.dev02.zhongcaiweiyou.com/soc');

        var ws = new WebSocket('ws://127.0.0.1:10004/soc');

        // var ws = new WebSocket('wss://api.lottery.com.cn/fb/blackjack/soc');

        ws.onmessage = function(event)
        {
            var table = document.getElementById('message');

            table.insertRow().insertCell().innerHTML = event.data;

        };


        //打开事件
        ws.onopen = function()
        {

            var info = "这是来自客户端的消息" + location.href + new Date();

            //var table = document.getElementById('message');

            // table.insertRow().insertCell().innerHTML = info;

            //ws.send(info);

        };
    //关闭事件

        ws.onclose = function()
        {

            var table = document.getElementById('message');

            table.insertRow().insertCell().innerHTML = "连接关闭";

        };

        //发生了错误事件

        ws.onerror = function()
        {

            var table = document.getElementById('message');

            table.insertRow().insertCell().innerHTML = "连接发生错误";

        };


        //关闭事件
        ws.onclose = function() {

            alert("Socket已关闭");
        };
        
//发生了错误事件

        ws.onerror = function() {

            alert("发生了错误");

        };


        //事件处理函数,当下拉列表选择改变时,触发该函数
        function change(id)
        {
           ws.send("这是来自客户端的消息" + location.href + new Date());

        }

    </script>

</head>
<body>
<table id='message'></table>

<button type="button" id="btnSend" onclick="change()">Click Me!</button>
</body>
</html>

后端:

# -*- coding: utf-8 -*-
__author__ = 'liwf'
import tornado.ioloop
import tornado.web
import tornado.httpserver
import tornado.options, tornado.httpclient
import tornado.web
import tornado.gen
import tornado.httpclient
import tornado.gen

import tornado.websocket

class Application(tornado.web.Application):
    def __init__(self):
        handlers = [
            ('/soc', SocketHandler),
        ]
        settings = dict(
            # login_url = "/auth/login",
            debug=True,
        )
        super(Application, self).__init__(handlers, **settings)

class SocketHandler(tornado.websocket.WebSocketHandler):
    clients = set()

    #解决跨域问题
    def check_origin(self, origin):
        #parsed_origin = urllib.parse.urlparse(origin)
        #return parsed_origin.netloc.endswith(".mydomain.com")
        return True

    @staticmethod
    def send_to_all(message):
        for c in SocketHandler.clients:
            c.write_message(message)

    def open(self):
        self.write_message('Welcome to WebSocket')
        SocketHandler.send_to_all(str(id(self)) + ' has joined')
        SocketHandler.clients.add(self)

    def on_message(self, message):
        SocketHandler.send_to_all(str(id(self)) + ' has joined')
        #self.write_message(message)

    def on_close(self):
        SocketHandler.clients.remove(self)
        SocketHandler.send_to_all(str(id(self)) + ' has left')

def main():
    tornado.options.parse_command_line()
    http_server = Application()

    http_server.listen(10003, xheaders=True)  # xheaders=True为了可以获取到header信息
    print('listening on %s ...' % 10003)

    tornado.ioloop.IOLoop.current().start()


if __name__ == "__main__":
    main()