Python Flask, come impostare il tipo di contenuto


176

Sto usando Flask e restituisco un file XML da una richiesta get. Come posso impostare il tipo di contenuto su xml?

per esempio

@app.route('/ajax_ddl')
def ajax_ddl():
    xml = 'foo'
    header("Content-type: text/xml")
    return xml

Risposte:


255

Prova in questo modo:

from flask import Response
@app.route('/ajax_ddl')
def ajax_ddl():
    xml = 'foo'
    return Response(xml, mimetype='text/xml')

Il tipo di contenuto effettivo si basa sul parametro mimetype e sul set di caratteri (il valore predefinito è UTF-8).

Gli oggetti di risposta (e richiesta) sono documentati qui: http://werkzeug.pocoo.org/docs/wrappers/


1
È possibile impostare queste e altre opzioni a livello globale (ovvero: impostazione predefinita)?
earthmeLon

10
@earthmeLon, crea una sottoclasse di flask.Response, sovrascrive l' default_mimetypeattributo class e impostalo come app.response_class werkzeug.pocoo.org/docs/wrappers/… flask.pocoo.org/docs/api/#flask.Flask.response_class
Simon Sapin

@earthmeLon: se si imposta app.response_classcome sottolinea Simon, ricordarsi di utilizzare app.make_responseper ottenere l'istanza di risposta come indicato nella risposta di seguito .
Martin Geisler,

Le richieste con browser o postino funzionano bene con questo approccio, tuttavia l'arricciatura non funziona bene con l'oggetto Response restituito. Curl stamperà semplicemente "Trovato". Con l'arricciatura "return content, status_code, header" sembra funzionare meglio.
fuma,

144

Semplice come questo

x = "some data you want to return"
return x, 200, {'Content-Type': 'text/css; charset=utf-8'}

Spero che sia d'aiuto

Aggiornamento: utilizzare questo metodo perché funzionerà con python 2.xe python 3.x

e in secondo luogo elimina anche il problema dell'intestazione multipla.

from flask import Response
r = Response(response="TEST OK", status=200, mimetype="application/xml")
r.headers["Content-Type"] = "text/xml; charset=utf-8"
return r

15
La soluzione più semplice Sicuramente dovrebbe essere la risposta accettata
Omer Dagan,

C'è un inconveniente: ti consente solo di aggiungere intestazioni. Quando l'ho fatto, ho finito con due intestazioni Content-Type in risposta: una di default e una aggiunta.
omikron,

1
@omikron Ho aggiornato la risposta, prova il nuovo metodo che dovrebbe funzionare.
Harsh Daftary,

48

Mi piace e ho votato a favore della risposta di @Simon Sapin. Alla fine ho preso una virata leggermente diversa e ho creato il mio decoratore:

from flask import Response
from functools import wraps

def returns_xml(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        r = f(*args, **kwargs)
        return Response(r, content_type='text/xml; charset=utf-8')
    return decorated_function

e usalo così:

@app.route('/ajax_ddl')
@returns_xml
def ajax_ddl():
    xml = 'foo'
    return xml

Penso che sia leggermente più comodo.


3
Quando si restituiscono sia una risposta che un codice di stato come return 'msg', 200, ciò comporterà ValueError: Expected bytes. Invece, cambia il decoratore in return Response(*r, content_type='whatever'). Disimballerà la tupla in argomenti. Grazie però, per una soluzione elegante!
Felix,

24

Usa il metodo make_response per ottenere una risposta con i tuoi dati. Quindi impostare l' attributo mimetype . Infine restituisci questa risposta:

@app.route('/ajax_ddl')
def ajax_ddl():
    xml = 'foo'
    resp = app.make_response(xml)
    resp.mimetype = "text/xml"
    return resp

Se lo usi Responsedirettamente, perdi la possibilità di personalizzare le risposte impostando app.response_class. Il make_responsemetodo utilizza il app.responses_classper rendere l'oggetto risposta. In questo puoi creare la tua classe, aggiungere fare in modo che l'applicazione la usi a livello globale:

class MyResponse(app.response_class):
    def __init__(self, *args, **kwargs):
        super(MyResponse, self).__init__(*args, **kwargs)
        self.set_cookie("last-visit", time.ctime())

app.response_class = MyResponse  

Questa è essenzialmente la risposta accettata di SimonSapin riconfezionata.
J0e3gan,

@ J0e3gan grazie. Ho ampliato la mia risposta per spiegare meglio perché usare make_responseè meglio che usareResponse
Marianna Vassallo

14
from flask import Flask, render_template, make_response
app = Flask(__name__)

@app.route('/user/xml')
def user_xml():
    resp = make_response(render_template('xml/user.html', username='Ryan'))
    resp.headers['Content-type'] = 'text/xml; charset=utf-8'
    return resp

2
Penso che questa risposta sia importante perché chiarisce come cambiare le intestazioni su qualcosa da un render_template.
A Hettinger,

5

Di solito non è necessario creare l' Responseoggetto da soli perché se make_response()ne occuperà per te.

from flask import Flask, make_response                                      
app = Flask(__name__)                                                       

@app.route('/')                                                             
def index():                                                                
    bar = '<body>foo</body>'                                                
    response = make_response(bar)                                           
    response.headers['Content-Type'] = 'text/xml; charset=utf-8'            
    return response

Un'altra cosa, sembra che nessuno abbia menzionato il after_this_request, voglio dire qualcosa:

after_this_request

Esegue una funzione dopo questa richiesta. Ciò è utile per modificare gli oggetti risposta. Alla funzione viene passato l'oggetto risposta e deve restituire lo stesso o uno nuovo.

quindi possiamo farlo con after_this_request, il codice dovrebbe apparire così:

from flask import Flask, after_this_request
app = Flask(__name__)

@app.route('/')
def index():
    @after_this_request
    def add_header(response):
        response.headers['Content-Type'] = 'text/xml; charset=utf-8'
        return response
    return '<body>foobar</body>'

4

Puoi provare il seguente metodo (python3.6.2) :

caso uno :

@app.route('/hello')
def hello():

    headers={ 'content-type':'text/plain' ,'location':'http://www.stackoverflow'}
    response = make_response('<h1>hello world</h1>',301)
    response.headers = headers
    return response

caso due :

@app.route('/hello')
def hello():

    headers={ 'content-type':'text/plain' ,'location':'http://www.stackoverflow.com'}
    return '<h1>hello world</h1>',301,headers

Sto usando Flask. E se vuoi restituire json, puoi scrivere questo:

import json # 
@app.route('/search/<keyword>')
def search(keyword):

    result = Book.search_by_keyword(keyword)
    return json.dumps(result),200,{'content-type':'application/json'}


from flask import jsonify
@app.route('/search/<keyword>')
def search(keyword):

    result = Book.search_by_keyword(keyword)
    return jsonify(result)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.