英文:
Extending Flask REST API with WebSockets
问题
我目前正在扩展使用Flask-RESTPlus创建的现有REST API,以支持WebSocket。我的想法是创建一个符合Web Thing Model标准的Web Thing(网关)。在我的用例中,“Things”会动态添加或移除。
当前的设置允许消费者通过HTTP GET请求到**/thingId/properties/temperature**来获取Thing(例如温度传感器)的最新值。实际上,这些值是从Kafka中消费并临时存储在Redis中。
现在我想知道如何扩展这个设置,使消费者不仅可以轮询最新的值,还可以使用WebSockets订阅Thing的属性。我有一个可行的解决方案,其中我为每个属性创建“Rooms”,但这需要两个单独的服务器和端点的复制。
对于REST,我有
@app.route('/<thingId>/properties/<propertyId>')
# 获取最新数据点
return latestDatapoint
对于Flask-SocketIO,我有
@socketio.on('join')
def on_join(data):
username = data['username']
room = data['room'] # 例如 /thingId/properties/temperature
join_room(room)
send(username + ' has entered the room.', room=room)
然后,我将数据从Kafka中接收的正确房间中转发。
在客户端上,我需要连接到WebSocket服务器并加入房间
socket.on('connection', function(socket){
socket.emit('join', 'some room');
});
这个实现可以工作,但我非常希望有一种替代工作流程,就像下图所示,其中客户端连接到与REST API中相同的端点,但使用WebSocket协议而不是加入房间等。
您有没有想法,是否已经存在这样的实现或者是否可行实现?
英文:
I am currently working on extending my existing REST API created using Flask-RESTPlus with WebSocket support. The idea is to create a Web Thing Model compliant Web Thing (Gateway). The "Things" in my use-case are dynamically added or removed.
The current setup allows a consumer to fetch the latest values from a Thing, e.g. temperature sensor, using a HTTP GET request to /thingId/properties/temperature. The values are in reality consumed from Kafka and temporarily stored in Redis.
Now I am wondering how I can extend this setup and allow the consumer to not only poll the latest values, but subscribe to the property of a Thing using WebSockets. I have a working solution where I create "Rooms" for each property, but this requires two separate servers and duplication of endpoints.
For REST I have
@app.route('/<thingId>/properties/<propertyId>')
# get latest datapoint
return latestDatapoint
For Flask-SocketIO I have
@socketio.on('join')
def on_join(data):
username = data['username']
room = data['room'] # e.g. /thingId/properties/temperature
join_room(room)
send(username + ' has entered the room.', room=room)
and then I'm forwarding the data to the correct room as it comes in from Kafka.
On the client side I then need to connect to the WebSocket server and join the room
socket.on('connection', function(socket){
socket.emit('join', 'some room');
});
This implementation works, but I was strongly hoping for an alternative workflow as shown in the figure below where the client connects to the same endpoint used in the REST API, but with the WebSocket protocol instead of joining rooms etc.
Do you have any idea if this already exists or is feasible to implement?
答案1
得分: 7
Here is the translated content:
我有一个可行的解决方案,其中我为每个属性创建了"Rooms",但这需要两个单独的服务器和端点的重复。
Socket.IO服务器和您的HTTP服务器不一定需要分开,在所有支持的配置中,您可以使用单个服务器托管HTTP和Socket.IO应用程序。
我也没有看到端点的重复,但也许这是因为您将Socket.IO事件处理程序视为端点,实际上它们并不是。在Socket.IO中,在HTTP意义上只有一个端点,因为所有Socket.IO流量都传输在单一URL上。您的事件处理程序只是这样的函数,当某些事件在Socket.IO端点上出现时会被调用。
客户端连接到与REST API中使用的相同端点,但使用WebSocket协议,而不是加入房间等。
所以您希望客户端为要观看的每个内容建立一个单独的WebSocket连接?这似乎对资源要求很高,而且不太可扩展。如果客户端需要观看100个内容,那么它将不得不维护100个WebSocket连接。请注意,大多数浏览器限制了它们可以同时打开的WebSocket连接的数量,每页和全局都有。
Socket.IO是建立在WebSocket和HTTP之上的更高级别协议。如果您仍然喜欢直接使用WebSocket,那么您可以选择其中任何可用的开源WebSocket服务器,而不是使用Socket.IO来实现您的应用程序。这里有我头脑中的一些Python选项:
- eventlet
- gevent-websocket
- websockets (asyncio)
- Tornado (asyncio)
您将失去一些Socket.IO提供的非常方便的功能:
- 自动重新连接
- 通过长轮询自动支持非WebSocket客户端
- 基于事件的分发
- 房间
因此,您需要确保这些不是重要的功能,或者您愿意在WebSocket服务器上直接实现它们。
英文:
> I have a working solution where I create "Rooms" for each property, but this requires two separate servers and duplication of endpoints.
The Socket.IO server and your HTTP server do not necessarily need to be separate, In all supported configurations you can host HTTP and Socket.IO applications with a single server.
I also don't see the endpoint duplication, but maybe this is because you think of Socket.IO event handlers as endpoints, while in fact they are not. With Socket.IO there is a single endpoint in the HTTP sense, since all Socket.IO traffic travels on a single URL. Your event handlers are just that, functions that are invoked when certain events pop up on the Socket.IO endpoint.
> where the client connects to the same endpoint used in the REST API, but with the WebSocket protocol instead of joining rooms etc.
So you want your client to establish a separate WebSocket connection for each thing it wants to watch? That seems a bit resource intensive and not very scalable to me. If the client needs to watch 100 things, then it will have to maintain 100 WebSocket connections. Keep in mind that most browsers cap the number of WebSocket connections they can have open at a time, both per page and globally.
Socket.IO is a higher-level protocol that is built on top of WebSocket and HTTP. If you still prefer to use WebSocket directly, then you can take any of the available open source WebSocket servers and implement your application with that instead of Socket.IO. Here are a few options for Python off the top of my mind:
- eventlet
- gevent-websocket
- websockets (asyncio)
- Tornado (asyncio)
You are going to lose a few things that Socket.IO offers that are very handy:
- Automatic reconnections
- Automatic support for non-WebSocket clients via long-polling
- Event-based dispatching
- Rooms
So you need to make sure these are not important features, or you are okay implementing them yourself directly on the WebSocket server.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论