2012-05-18 12 views
6

Ich verwende Python Flask + nginx mit FCGI. Python Flask + nginx fcgi - Ausgabe große Antwort?

Auf einigen Anfragen habe ich ausgeben große Antworten. Normalerweise werden diese Antworten von einem Socket abgerufen. Zur Zeit mache ich die Antwort wie folgt aus:

response = [] 
while True: 
    recv = s.recv(1024) 
    if not recv: break 
    response.append(recv) 
s.close() 
response = ''.join(response) 

return flask.make_response(response, 200, { 
              'Content-type': 'binary/octet-stream', 
              'Content-length': len(response), 
              'Content-transfer-encoding': 'binary', 
              }) 

Das Problem ist, ich weiß nicht wirklich die Daten benötigen. Ich habe auch eine Möglichkeit, die genaue Antwortlänge zu ermitteln, die aus dem Socket abgerufen werden soll. Also muß ich einen guten Weg, um die HTTP-Header senden, dann starten Sie direkt aus der Steckdose outputing, anstatt sie im Speicher zu sammeln und dann (wahrscheinlich durch eine Art von einem Strom) nginx zu liefern.

Ich konnte nicht die Lösung für dieses scheinbar weit verbreitetes Problem zu finden. Wie würde das erreicht werden?

Vielen Dank!

Antwort

10

Wenn response in flask.make_response ein iterable ist, wird es iteriert, um die Antwort zu erzeugen, und jede Zeichenfolge wird für sich in den Ausgabestrom geschrieben.

, was das bedeutet ist, dass Sie auch einen Generator zurückgeben kann, die den Ausgang ergeben, wenn über iteriert. Wenn Sie die Inhaltslänge kennen, können Sie diese als Header übergeben (und sollten dies auch tun).

ein einfaches Beispiel:

from flask import Flask 
app = Flask(__name__) 
import sys 
import time 
import flask 

@app.route('/') 
def generated_response_example(): 
    n = 20 
    def response_generator(): 
     for i in range(n): 
      print >>sys.stderr, i 
      yield "%03d\n" % i 
      time.sleep(.2) 

    print >>sys.stderr, "returning generator..." 
    gen = response_generator() 

    # the call to flask.make_response is not really needed as it happens imlicitly 
    # if you return a tuple. 
    return flask.make_response(gen ,"200 OK", {'Content-length': 4*n}) 

if __name__ == '__main__': 
    app.run() 

, wenn Sie dies ausführen und versuchen, es in einem Browser, sollten Sie eine schöne incemental Zählung sehen ...

(der Inhaltstyp nicht gesetzt ist, weil es scheint wenn ich das tue, dass mein Browser wartet, bis der gesamte Inhalt hat vor dem Rendern der Seite gestreamt wurde. wget -qO - localhost:5000 nicht über diese Probleme haben.