基本 demo,列出重要的一些问题
main.js
文件...
import VueSocketio from 'vue-socket.io'
Vue.use(new VueSocketio({
debug: true,
connection: 'https://domain/chatroom'
}))
...
注意点:
chatroom
为后端 flask-socketio
中 namespace
(此处为静态命令空间,动态命令空间设置较为复杂)
根据官方文档,可以额外设置
options: {path: '/chatroom'}
,则后端nginx
中/socketio
改为/chatroom
;不设置,后端默认/socketio
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
连接,response
和 chat_message
分别用来监听后端不同回复,并分别做处理onMsgSubmit
用户输入后,向后端 user_input
传输数据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)
跨域,在 flask
和 flask-socketio
中设置后,nginx
中不用再设置
request.sid
获取 session_id
,每个用户单独一个聊天室
向特定用户 sid
回复
socketio.emit('chat_message', {},namespace='/chatroom',room=sid)
gunicorn -b 127.0.0.1:8211 -k eventlet -w 1 wss_app:app
pip install eventlet
-w
必须设为 1,否则报错 invalid session
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/HTTPS
和 WebSocket
需要路由到不同端口HTTP/HTTPS
通过 domain/chatroom/xxx
访问,其中 /chatroom/
中后一个 /
不能省略WebSocket
通过 domain/socket.io
访问,/socket.io
后面不需要添加 /
跨域设置
nginx
和 flask/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.
参考官方文档,Github issues 即可
Flask-SocketIO Document
Vue-Socket.io Github