2012-05-18 5 views
6

Sto usando Python Flask + nginx con FCGI.Python Flask + nginx fcgi - genera una risposta elevata?

Su alcune richieste, devo produrre risposte grandi. Di solito quelle risposte vengono recuperate da un socket. Attualmente sto facendo la risposta in questo modo:

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', 
              }) 

Il problema è che in realtà non ho bisogno dei dati. Ho anche un modo per determinare la lunghezza esatta della risposta da prelevare dal socket. Quindi ho bisogno di un buon modo per inviare le intestazioni HTTP, quindi avviare l'output direttamente dal socket, invece di raccoglierlo in memoria e quindi fornire a nginx (probabilmente da una sorta di stream).

Non sono riuscito a trovare la soluzione a questo problema apparentemente comune. Come sarebbe stato realizzato?

Grazie!

risposta

10

se response in flask.make_response è un iterabile, verrà iterato per produrre la risposta e ogni stringa verrà scritta nel proprio flusso di output.

ciò significa che è anche possibile restituire un generatore che produrrà l'output quando viene ripetuto. se conosci la lunghezza del contenuto, puoi (e dovresti) passarlo come intestazione.

un semplice esempio:

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() 

se si esegue questo e provare in un browser, si dovrebbe vedere una bella conteggio incemental ...

(il tipo di contenuto non è impostato perché sembra se lo faccio il mio browser aspetta che tutto il contenuto sia stato trasmesso in streaming prima di eseguire il rendering della pagina. wget -qO - localhost:5000 non ha questo problema