2012-11-14 2 views
24

Flask의 스트리밍 사용 방법을 파악할 수 없습니다. 여기에 내 코드입니다 :Python 및 Flask로 데이터 스트리밍

@app.route('/scans/') 
def scans_query(): 
    url_for('static', filename='.*') 
    def generate(): 
     yield render_template('scans.html') 
     for i in xrange(50): 
      sleep(.5) 
      yield render_template('scans.html', **locals()) 
    return Response(stream_with_context(generate())) 

내 템플릿 :

<p>{% i %}</p> 

나는 0.5 초마다 변경 페이지에 카운터를보고 싶습니다. 대신, 내가 얻은 가장 가까운 것은 다음 줄에 각 번호를 인쇄하는 페이지입니다.

답변

38

페이지의 기존 콘텐츠를 바꾸려면 javascript가 필요합니다. 즉, 보내거나 작성하여 긴 폴링, 웹 소켓 등을 사용할 수 있습니다. 여러 가지 방법이 있습니다. 여기에 server send events을 사용하는 방법이 있습니다. :

연결이 끊어지면

<!doctype html> 
<title>Server Send Events Demo</title> 
<style> 
    #data { 
    text-align: center; 
    } 
</style> 
<script src="http://code.jquery.com/jquery-latest.js"></script> 
<script> 
if (!!window.EventSource) { 
    var source = new EventSource('/'); 
    source.onmessage = function(e) { 
    $("#data").text(e.data); 
    } 
} 
</script> 
<div id="data">nothing received yet</div> 

브라우저 3 초에 기본적으로 다시 연결 : static/index.html

. 서버에 보낼 내용이 더없는 경우 404를 반환하거나 다음 요청에 대한 응답으로 'text/event-stream' 콘텐츠 유형 이외를 보낼 수 있습니다. 서버에 더 많은 데이터가 있더라도 클라이언트 측에서 중지하려면 source.close()을 호출 할 수 있습니다.

참고 : 스트림이 무한 될 운명되지 않은 경우에는 (무한 <iframe> 기술) 텍스트를 대체하는 자바 스크립트 조각을 보내, 예를 들어, 다른 기술 (하지 SSE)를 사용 :

#!/usr/bin/env python 
import time 
from flask import Flask, Response 

app = Flask(__name__) 


@app.route('/') 
def index(): 
    def g(): 
     yield """<!doctype html> 
<title>Send javascript snippets demo</title> 
<style> 
    #data { 
    text-align: center; 
    } 
</style> 
<script src="http://code.jquery.com/jquery-latest.js"></script> 
<div id="data">nothing received yet</div> 
""" 

     for i, c in enumerate("hello"): 
      yield """ 
<script> 
    $("#data").text("{i} {c}") 
</script> 
""".format(i=i, c=c) 
      time.sleep(1) # an artificial delay 
    return Response(g()) 


if __name__ == "__main__": 
    app.run(host='localhost', port=23423) 

내가 인라인 한 여기에 HTML은 더 이상 아무것도 없다는 것을 보여줍니다 (마법 없음). 다음은 위와 같지만 템플릿을 사용하는 것과 동일합니다 :

#!/usr/bin/env python 
import time 
from flask import Flask, Response 

app = Flask(__name__) 


def stream_template(template_name, **context): 
    # http://flask.pocoo.org/docs/patterns/streaming/#streaming-from-templates 
    app.update_template_context(context) 
    t = app.jinja_env.get_template(template_name) 
    rv = t.stream(context) 
    # uncomment if you don't need immediate reaction 
    ##rv.enable_buffering(5) 
    return rv 


@app.route('/') 
def index(): 
    def g(): 
     for i, c in enumerate("hello"*10): 
      time.sleep(.1) # an artificial delay 
      yield i, c 
    return Response(stream_template('index.html', data=g())) 


if __name__ == "__main__": 
    app.run(host='localhost', port=23423) 

경우 templates/index.html :

<!doctype html> 
<title>Send javascript with template demo</title> 
<style> 
    #data { 
    text-align: center; 
    } 
</style> 
<script src="http://code.jquery.com/jquery-latest.js"></script> 
<div id="data">nothing received yet</div> 
{% for i, c in data: %} 
<script> 
    $("#data").text("{{ i }} {{ c }}") 
</script> 
{% endfor %} 
+0

당신이 (특히 내가 SSE 데모와 함께 연주 해요)에서 제공하는 데모는 하나의 클라이언트에 대해 작동합니다. 새 브라우저 창을 열어 페이지 스트리밍 데이터에 액세스하려고하면 이전 페이지를 닫거나 중지 할 때까지 아무런 반응이 없습니다. 그리고 나서 카운터는 0에서 다시 시작합니다. 어떻게하면이 모든 정보를 액세스하려고하는 클라이언트가 동일한 데이터/카운터를 볼 수 있도록 응용 프로그램을 시작한 시점부터 다시 계산합니까? 별도의 스레드에서 카운터를 실행해야한다고 가정하고 있지만이를 구현하는 방법을 모르겠습니다. –

+1

@DavidMarx : 적어도 두 가지 질문이 있습니다. (1) 플라스크에서 여러 동시 클라이언트를 지원하는 방법은 무엇입니까? - 답 : 어떤 wsgi 앱에서와 같은 방식으로, 예를 들어 gunicorn (2)을 사용하여 여러 클라이언트의 동일한 카운터에 대한 액세스 권한을 제공 할 수 있습니까? - 서버 프로그램의 공유 데이터에 대한 액세스를 제공하는 것과 같은 방법으로, 예를 들어 단일 작업자라고 가정합니다. 전역 반복기를 정의하고 루프에서'next (it) '를 호출합니다. 어쨌든, 이들은 별도의 질문입니다. 특정 문제와 관련된 새로운 질문을하십시오. – jfs

+0

감사합니다. 좀 더 집중된 주제로 새로운 질문을 게시했습니다 : http://stackoverflow.com/questions/33877359/building-a-front-end-webapp-for-a-real-time-data-stream-in- python –

6

난 당신이 그런 템플릿을 사용하려고하는 경우, 당신은 여기에 주어진 stream_template 기능을 사용할 필요가 있다고 생각 : http://flask.pocoo.org/docs/patterns/streaming/#streaming-from-templates

내가 이것을 테스트하지 않았다, 그러나 그것은과 같습니다

def stream_template(template_name, **context): 
    app.update_template_context(context) 
    t = app.jinja_env.get_template(template_name) 
    rv = t.stream(context) 
    rv.enable_buffering(5) 
    return rv 

@app.route('/scans/') 
def scans_query(): 
    url_for('static', filename='.*') 
    def generate(): 
     for i in xrange(50): 
      sleep(.5) 
      yield i 
    return Response(stream_template('scans.html', i=generate())) 
관련 문제