Flask SocketIO服务端Tweepy流数据无法发送到客户端(Twilio功能正常)
问题原因
- tweepy异步流运行在独立的后台线程,不属于Flask-SocketIO的工作线程上下文,直接调用
sio.emit()时,因为没有匹配的客户端会话上下文,消息不会被实际推送给客户端。 - Twilio的请求走Flask HTTP路由,属于应用的工作线程,和SocketIO运行环境兼容,所以可以正常发送消息。
- 额外设计问题:你把
handle_message用@sio.event装饰,它原本的作用是处理客户端发来的handle_message事件,虽然直接调用不会报错,但不符合设计逻辑,建议把公共转发逻辑抽离为独立函数。
修复方案
修改server.py的核心代码如下:
- 抽离公共转发逻辑,跨线程调用emit时添加
broadcast=True参数(会将消息推送给所有已连接的SocketIO客户端) - 对tweepy返回的JSON字符串数据先做解析再转发
- 优化tweepy流的启动逻辑,避免多个客户端连接时重复启动流
from flask import Flask, json, request from twilio.twiml.messaging_response import MessagingResponse from flask_socketio import SocketIO import tweepy import json PATH = '/path/to/credentials/' with open(PATH, "r") as file: credentials = json.load(file) app = Flask(__name__) app.debug = True app.config['SECRET_KEY'] = 'abc123' sio = SocketIO(app, cors_allowed_origins="*") auth = tweepy.OAuthHandler(credentials['CONSUMER_KEY'], credentials['CONSUMER_SECRET']) auth.set_access_token(credentials['ACCESS_TOKEN'], credentials['ACCESS_SECRET']) api = tweepy.API(auth) # 全局标记,避免重复启动流 stream_started = False # 抽离公共转发逻辑,不要用@sio.event装饰的函数做普通调用 def forward_message(message): print("This is the message received: ", message) # 关键参数broadcast=True:跨线程发送时必须加,才能推送给所有客户端 sio.emit('handle_message', message, broadcast=True) class MyListener(tweepy.StreamListener): def on_status(self, status): print('status') def on_data(self, data): # 先把tweepy返回的JSON字符串转为字典再转发 tweet_data = json.loads(data) forward_message(tweet_data) def on_error(self, status): print('error') print(status) stream_listener = MyListener() # twilio sms route @app.route('/sms', methods=['POST']) def sms(): number = request.form['From'] message_body = request.form['Body'] message_data = {"number": number, "msg": message_body} resp = MessagingResponse() resp.message('Hello {}, you said: {}'.format(number, message_body)) forward_message(message_data) return str(resp) # flask-socketio stuff @sio.on('connect') def connect(): global stream_started print('connected') sio.emit('client_connected', "you connected") search_term = "#mysearchterm" # 只启动一次流 if not stream_started: stream = tweepy.Stream(auth=api.auth, listener=stream_listener) stream.filter(track=[search_term], is_async=True) stream_started = True sio.emit('client_connected', "the search term is {}".format(search_term)) @sio.on('disconnect') def disconnect(): print('Client Disconnected') # 保留这个函数用来处理客户端主动发来的handle_message事件 @sio.event def handle_message(message): forward_message(message) if __name__ == '__main__': sio.run(app)
验证
修改后重启服务,推特流收到的消息就可以正常推送给客户端了,Twilio的消息转发逻辑也不受影响。
内容的提问来源于stack exchange,提问作者ec.lemmon
相关产品推荐
相关产品推荐

