websocket前后端分离demo(vue-socket.io + flask-socketio + nginx)

4 篇文章 0 订阅

基本 demo,列出重要的一些问题

1 vue-socket.io 配置

1.1 main.js 文件
...
import VueSocketio from 'vue-socket.io'

Vue.use(new VueSocketio({
  debug: true,
  connection: 'https://domain/chatroom'
}))

...

注意点:

  • chatroom 为后端 flask-socketionamespace(此处为静态命令空间,动态命令空间设置较为复杂)

    根据官方文档,可以额外设置 options: {path: '/chatroom'} ,则后端 nginx/socketio 改为 /chatroom;不设置,后端默认 /socketio

1.2 app.vue
<script>
import axios from 'axios'

export default{
    data() {
        return {
            messages: []
        }
    },
    created() {
        const url = 'https://domain/chatroom/index'
        axios({
            method: 'get',
            url: url,
            data: {
                msg: 'hello'
            }
        }).then(res => {
            console.log(res)
        })
    },
    sockets: {
        connect: function() {
          console.log('socket connected')
        },
        # 监听后端传来数据(自定义提示)
        response: function(res) {
          this.$message.success(res.msg)
        },
        # 监听后端传来数据(自定义消息)
        chat_message: function(msg) {
          this.messages.push(msg)
    },
    methods: {
        onMsgSubmit(msg){
            # 用户点击,提交用户输入
            this.$socket.emit('user_input', msg)
        }
    }
    }
}
</script>
  • 创建页面时,axios 进行 HTTP/HTTPS 请求
  • sockets 中自动创建 WebSocket 连接,responsechat_message 分别用来监听后端不同回复,并分别做处理
  • onMsgSubmit 用户输入后,向后端 user_input 传输数据

2 flask-socketio 配置

2.1 demo 代码
from threading import Lock
from flask import Flask, request
from flask_socketio import SocketIO, emit, join_room, \
    leave_room, close_room, rooms, disconnect
from flask_cors import CORS

app = Flask(__name__)
app.config['SECRET_KEY'] = 'chatroom'
CORS(app, supports_credentials=True)
socketio = SocketIO(app, cors_allowed_origins="*")

def background_chat(msg, sid):
    for _ in range(3):
        socketio.emit('chat_message', {'content': msg + "?"},
                      namespace='/chatroom',
                      room=sid)
       	socketio.sleep(3)

@app.route('/index', methods=['GET'])
def index():
    return 'welcome to the chatroom!'

@socketio.on('join', namespace='/chatroom')
def join_chat(message):
    """创建聊天室
    """
    join_room(request.sid)

    thread = socketio.start_background_task(background_chat, msg,request.sid)
    emit('response', {'msg': '创建聊天室成功'})

@socketio.on('leave', namespace='/chatroom')
def leave_chat(message):
    """离开聊天室,仅删除当前用户
    """

@socketio.on('close', namespace='/chatroom')
def close_chat(message):
    """关闭聊天室,将所有用户移出
    """

@socketio.on('user_input', namespace='/chatroom')
def user_input(message):
    """获取用户输入
    """
    sid = request.sid
	# TODO

@socketio.on('connect', namespace='/chatroom')
def connect():
    """创建socket链接
    用户进入浏览器页面,自动加入
    """
    print('connect', request.sid)


@socketio.on('disconnect', namespace='/chatroom')
def disconnect():
    """关闭socket链接
    用户关闭浏览器页面,自动退出
    """
    print('Client disconnected', request.sid)

if __name__ == '__main__':
    socketio.run(app, debug=True, host="127.0.0.1", port=5000)

  • 跨域,在 flaskflask-socketio 中设置后,nginx 中不用再设置

  • request.sid 获取 session_id,每个用户单独一个聊天室

  • 向特定用户 sid 回复

    socketio.emit('chat_message', {},namespace='/chatroom',room=sid)

2.2 启动
gunicorn -b 127.0.0.1:8211 -k eventlet -w 1 wss_app:app
  • pip install eventlet
  • -w 必须设为 1,否则报错 invalid session

3 nginx 配置

server {
        listen 80;
        server_name api.mcc.khay.site;
        rewrite ^(.*)$ https://$host$1 permanent;
}

server {
        listen 443 ssl http2;
        server_name domain;

        access_log  /var/log/nginx/domain.access.log;
        error_log /var/log/nginx/domain.error.log;

        ssl on;
        ssl_certificate /etc/letsencrypt/live/domain/cert.pem;
        ssl_certificate_key /etc/letsencrypt/live/domain/privkey.pem;

        ssl_session_timeout 5m;

        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;

        location /static {
                alias /var/www/mcc/website/static;
        }

  		location /chatroom/ {
                include proxy_params;
                proxy_pass http://127.0.0.1:8211/;
        }

        location /socket.io {
          #add_header Access-Control-Allow-Credentials true;
                include proxy_params;
                proxy_http_version 1.1;
                proxy_buffering off;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "Upgrade";
                proxy_pass http://127.0.0.1:8211/socket.io;
        }
}

注意点:

  • 同一个 flask 应用中,HTTP/HTTPSWebSocket 需要路由到不同端口
  • HTTP/HTTPS 通过 domain/chatroom/xxx 访问,其中 /chatroom/ 中后一个 / 不能省略
  • WebSocket 通过 domain/socket.io 访问,/socket.io 后面不需要添加 /

4 相关问题

  • 跨域设置

    • nginxflask/flask-socketio 只需要其中一个设置即可

    • nginx 设置 WebSocket 各种报错,未成功;HTTP/HTTPS 设置

      location / {
      	root /var/www/html;
      	index index.html index.htm;
      
          add_header Access-Control-Allow-Origin * always;
          add_header Access-Control-Allow-Headers "DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Cont
          ent-Type,Authorization, user-id" always;
          add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, PATCH, DELETE, HEAD" always;
          add_header Access-Control-Max-Age 86400 always;
      
      
          if ($request_method = 'OPTIONS') {
          return 204;
          }
      
          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_pass http://127.0.0.1:8200/;
      }
      
      • 如果 Header 中携带其他数据,直接在 Access-Control-Allow-Headers 中添加即可
    • flask/flask-socketio 设置

      pip install flask-cors

      from flask_cors import CORS
      ...
      app = Flask(__name__)
      CORS(app, supports_credentials=True) # HTTP/HTTPS 跨域
      socketio = SocketIO(app, cors_allowed_origins="*") # websocket 跨域
      
  • Invalid session

    • gunicorn 其中-w (即 workers) 必须设为 1

      参考官方文档说明

      Due to the limited load balancing algorithm used by gunicorn, it is not possible to use more than one worker process when using this web server. For that reason, all the examples above include the -w 1 option.

5 参考文档

参考官方文档,Github issues 即可

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值