python - 将 Flask-SocketIO 与 Node socket.io-client 或 ngx-socket-io 连接时出现问题
问题描述
目前我正在使用 Ionic 和 Flask_SocketIO 开发一个实时聊天应用程序
我确实需要 Flask 作为后端,因为我正在使用 Flask_login 处理身份验证。问题似乎出在我的应用程序的 nodejs-angular-ionic 方面。应用程序可以正确连接和验证,但是一旦我从 IonicClient 向其他客户端(例如来自网络)发出消息,它们似乎停止接收,但我仍然能够从这些客户端发出消息。服务器实际上确实将它们列为已连接。所以可能存在请求冲突。
如果我只使用来自网络的客户端,我的聊天会完美运行,这让我相信它与我们的 nodejs-angular-ionic-app 有关
FlaskBackend、WebClients 和 IonicClients 都不会显示错误消息。
FLASK_BACKEND:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_socketio import emit, join_room, leave_room, SocketIO, send, disconnect
import functools
from flask_login import current_user, LoginManager
from flask import g
from datetime import datetime
from itsdangerous import URLSafeTimedSerializer
from flask_socketio import ConnectionRefusedError
app = Flask(__name__)
app.config.from_pyfile('config.cfg')
socketio = SocketIO(app, manage_session=False, cors_allowed_origins='*') #http://127.0.0.1:5000
login = LoginManager(app)
db = SQLAlchemy(app)
room = None
def confirm_token(token, expiration=86400):
serializer = URLSafeTimedSerializer(app.config['SECRET_KEY'])
try:
id = serializer.loads(
token,
salt=app.config['SECURITY_PASSWORD_SALT'],
max_age=expiration
)
except:
return False
return id
from models import UserModel, MessageModel
@login.request_loader
def load_user_from_request(request):
# first, try to login using the api_key url arg
id = request.args.get('id')
if id:
id = confirm_token(id)
if id:
g.login_via_header = True
user = UserModel.query.filter_by(id=id).first()
db.session.close_all()
if user:
return user
else:
return None
else:
print("No id found")
return None
def authenticated_only(f):
@functools.wraps(f)
def wrapped(*args, **kwargs):
if not current_user.is_authenticated or current_user.is_anonymous:
print("current_user is anonymous")
disconnect()
else:
return f(*args, **kwargs)
return wrapped
@socketio.on('joined')
@authenticated_only
def joined(message):
"""Sent by clients when they enter a room.
A status message is broadcast to all people in the room."""
global room
room = message['room']
join_room(room)
emit('status', {'msg': str(current_user.first) + ' is now Online.'}, room=room, skip_sid=True)
print(current_user.first, "joined room no.", room)
@socketio.on('text')
@authenticated_only
def text(message):
"""Sent by a client when the user entered a new message.
The message is sent to all people in the room."""
global room
msg = MessageModel(
owner = current_user,
room = room,
message = str(message['msg']),
timestamp = datetime.utcnow()
)
try:
msg.save_to_db()
emit('message', {'msg': message['msg'],
'u_id': current_user.id,
'u_pp': current_user.profile_picture,
'u_name': current_user.first }, room=room, skip_sid=True)
print(current_user.first + ": " + str(message['msg']))
except Exception as e:
print(e)
raise
@socketio.on('disconnect')
def test_disconnect():
print("Bye", current_user.first)
global room
leave_room(room)
emit('status', {'msg': str(current_user.first) + ' is now Offline.'}, room=room, skip_sid=True)
if __name__ == '__main__':
socketio.run(app, host='0.0.0.0', port=3001)
离子:
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Socket } from 'ngx-socket-io';
const SOCKET_URL = 'http://192.168.0.125:3001?id='
@Component({
selector: 'app-job-detail',
templateUrl: './job-detail.page.html',
styleUrls: ['./job-detail.page.scss'],
})
export class JobDetailPage implements OnInit {
private id: string;
private token: string = "MQ.XoxlTg.Pjd8WcW_e2ywu5YeabBwToz53nM";
messages = [];
constructor(
private route: ActivatedRoute,
private socket: Socket,
) {
}
ngOnInit() {
this.id = this.route.snapshot.paramMap.get('id');
this.socket.ioSocket.io.opts.query = {cookie: false, transports: ['websocket']};
this.socket.ioSocket.io.uri = SOCKET_URL + this.token; //new uri
this.socket.connect(); //manually connection
this.socket.fromEvent('connect').subscribe( () => {
this.socket.emit('joined', {room: this.id});
});
this.socket.fromEvent('disconnect').subscribe(() => {
console.log("You disconnected from our chat servers")
})
//this.socket.fromEvent('status').subscribe(data => {
// console.log(data)
//});
}
sendMessage(msg) {
this.socket.emit('text', {
msg: msg
});
}
网页:
socket = io("http://192.168.0.125:3001?id={{chattoken}}", { transports: ['websocket'] });
socket.on('connect', function() {
socket.emit('joined', {room: room_id});
});
socket.on('disconnect', function() {
console.log("You disconnected from our Chat servers")
});
socket.on('status', function(data) {
console.log("Received A StatusUpdate")
$('#chat').html($('#chat').html() + '<div style="text-align: center">' + data.msg + '</div><br>');
$('#chat').scrollTop($('#chat')[0].scrollHeight);
});
socket.on('message', function(data) {
console.log("Received A Message")
if (data.u_id == user_id) {
$('#chat').html($('#chat').html() + outgoing_msg + data.msg + outgoing_msg_end);
} else {
var d = new Date();
var h = addZero(d.getHours());
var m = addZero(d.getMinutes());
if (data.u_pp == "missing") {
$('#chat').html($('#chat').html() + incoming_msg + "<div class=\"incoming_msg_img\"> <img src=\"{{ url_for('static', filename='images/missing.png') }}\"> </div>" + incoming_msg_middle + data.msg + incoming_msg_end + data.u_name +
" today, " + h + ":" + m + incoming_msg_end_1);
} else {
$('#chat').html($('#chat').html() + incoming_msg + "<div class=\"incoming_msg_img\" style=\"background-image: url('" + data.u_pp + "'); background-size:cover; border-radius: 4rem;\"> </div>" + incoming_msg_middle + data.msg +
incoming_msg_end + data.u_name + " today, " + h + ":" + m + incoming_msg_end_1);
}
}
$('#chat').scrollTop($('#chat')[0].scrollHeight);
});
经过进一步调查,我发现了这些问题: https ://github.com/miguelgrinberg/python-socketio/issues/47 https://github.com/miguelgrinberg/Flask-SocketIO/issues/253#issuecomment-233241257
但由于我也尝试了 ngx-socket-io 和 2016 年的问题,我认为它们不相关。
提前致谢,
氟草酮
解决方案
推荐阅读
- push - 可以在 HTTP/2 上推送 manifest.json 吗?我应该如何描述它?
- sql - 用于在 Azure 虚拟机中创建新 sql 数据库的 Arm 模板
- javascript - 承诺链竞争条件
- c# - 如何在 C# 的回调中检测服务器套接字已关闭
- excel - 在 Excel 或 Power Pivot 中确定除以另一列时的模式
- google-app-engine - 从服务帐户进行身份验证时访问 IAP 资源时出错 - 502 服务器错误
- intellij-idea - IntelliJ:无法为 Web 应用程序指定/创建应用服务器
- sql-server - Sqlcmd 使用 SQL Server 存储过程将数据导出到 csv
- rtmp - 如何在 RTMP 和 Video 上使用 YOLO 实时检测对象?
- conv-neural-network - 使用 YOLO3 进行对象检测