2012-09-01 18 views
37

Tôi đang cố gắng xây dựng một trang web nhỏ với chức năng đẩy máy chủ trên khung công tác web vi mô của Flask, nhưng tôi không biết liệu có một khuôn khổ để làm việc trực tiếp hay không.Làm cách nào để triển khai đẩy máy chủ trong khung công tác Flask?

Tôi đã sử dụng Juggernaut, nhưng có vẻ như không hoạt động với redis-py trong phiên bản hiện tại và Juggernaut đã không được dùng nữa gần đây.

Có ai có đề xuất với trường hợp của tôi không?

+6

[Đây là bài viết có liên quan từ tháng trước bởi Armin Ronacher, nhà phát triển chính của Flask.] (Http://lucumr.pocoo.org/2012/8/5/stateless-and-proud/) – dumbmatter

+0

related: [Streaming dữ liệu với Python và Flask] (http://stackoverflow.com/q/13386681/4279) – jfs

Trả lời

75

Hãy xem Server-Sent Events. Sự kiện được máy chủ gửi là API trình duyệt cho phép bạn tiếp tục mở ổ cắm cho máy chủ của mình, đăng ký một luồng cập nhật . Để biết thêm thông tin, hãy đọc Alex MacCaw (Tác giả của Juggernaut) đăng trên why he kills juggernaut và lý do tại sao đơn giản hơn Sự kiện do máy chủ gửi là trong trường hợp manny công cụ tốt hơn cho công việc hơn Websockets.

Giao thức thực sự dễ dàng. Chỉ cần thêm mimetype text/event-stream vào phản hồi của bạn. Trình duyệt sẽ giữ kết nối mở và lắng nghe các bản cập nhật. Sự kiện được gửi từ máy chủ là một dòng văn bản bắt đầu bằng data: và dòng mới sau.

data: this is a simple message 
<blank line> 

Nếu bạn muốn trao đổi dữ liệu có cấu trúc, chỉ cần đổ dữ liệu của bạn như json và gửi json qua dây.

Lợi thế là bạn có thể sử dụng SSE trong Flask mà không cần thêm Máy chủ. Có một đơn giản chat application example trên github mà sử dụng redis như một pub/phụ backend.

def event_stream(): 
    pubsub = red.pubsub() 
    pubsub.subscribe('chat') 
    for message in pubsub.listen(): 
     print message 
     yield 'data: %s\n\n' % message['data'] 


@app.route('/post', methods=['POST']) 
def post(): 
    message = flask.request.form['message'] 
    user = flask.session.get('user', 'anonymous') 
    now = datetime.datetime.now().replace(microsecond=0).time() 
    red.publish('chat', u'[%s] %s: %s' % (now.isoformat(), user, message)) 


@app.route('/stream') 
def stream(): 
    return flask.Response(event_stream(), 
          mimetype="text/event-stream") 

Bạn không cần sử dụng gunicron để chạy ứng dụng ví dụ . Chỉ cần chắc chắn để sử dụng luồng khi chạy ứng dụng, vì nếu không kết nối SSE sẽ chặn máy chủ phát triển của bạn:

if __name__ == '__main__': 
    app.debug = True 
    app.run(threaded=True) 

Về phía khách hàng mà bạn chỉ cần một chức năng xử lý Javascript mà sẽ được gọi khi một tin nhắn mới được đẩy từ máy chủ.

var source = new EventSource('/stream'); 
source.onmessage = function (event) { 
    alert(event.data); 
}; 

Server-Sent Events là supported bởi các trình duyệt Firefox, Chrome và Safari gần đây. Internet Explorer chưa hỗ trợ sự kiện Server-Sent, nhưng dự kiến ​​sẽ hỗ trợ họ trong Version 10. Có hai Polyfills khuyến cáo để hỗ trợ các trình duyệt cũ

+0

Xin chào @PeterSmith, tôi đã thử cách tiếp cận này, tuy nhiên, cảnh báo (event.data) không bao giờ xuất hiện. Tôi chạy ứng dụng Flask của tôi trong cổng 8000 và đẩy vào cổng 8001. Vì vậy, tôi đặt "var source = new EventSource ('http: // localhost: 8001/push');" và ứng dụng Flask có một trang mà người dùng có thể đăng nội dung nào đó. Bài đăng được phát và nhận bởi tất cả người dùng khác. Bạn có bất cứ ý tưởng? –

+0

Tại sao bạn chạy push trên một cổng khác? Một lý do cho SSE là nó chạy trong ứng dụng của bạn trên http bình thường. bạn đã chạy các ứng dụng bình của mình như thế nào? thông qua máy chủ phát triển? Bạn đã thêm luồng = True? Bạn đang dùng trình duyệt nào? –

+0

Hi @PeterHoffmann, tôi sử dụng lốc xoáy với Flask. Có thể tôi đặt dụ dụ ứng dụng và dụ pusher lại với nhau trong cơn lốc xoáy không? Nói xử lý khác nhau? Tôi có nên thiết lập đa luồng không? –

5

Như theo dõi tới @peter-hoffmann's answer, tôi đã viết một tiện ích Flask đặc biệt để xử lý các sự kiện do máy chủ gửi. Nó được gọi là Flask-SSE và là available on PyPI.Để cài đặt nó, chạy:

$ pip install flask-sse 

Bạn có thể sử dụng nó như thế này:

from flask import Flask 
from flask_sse import sse 

app = Flask(__name__) 
app.config["REDIS_URL"] = "redis://localhost" 
app.register_blueprint(sse, url_prefix='/stream') 

@app.route('/send') 
def send_message(): 
    sse.publish({"message": "Hello!"}, type='greeting') 
    return "Message sent!" 

Và để kết nối với dòng sự kiện từ Javascript, nó hoạt động như thế này:

var source = new EventSource("{{ url_for('sse.stream') }}"); 
source.addEventListener('greeting', function(event) { 
    var data = JSON.parse(event.data); 
    // do what you want with this data 
}, false); 

Documentation is available on ReadTheDocs. Lưu ý rằng bạn sẽ cần một máy chủ đang chạy Redis để xử lý pub/sub.