Python Flask, wie man den Inhaltstyp festlegt

176

Ich verwende Flask und gebe eine XML-Datei von einer Get-Anfrage zurück. Wie setze ich den Inhaltstyp auf XML?

z.B

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

Antworten:

254

Versuchen Sie es so:

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

Der tatsächliche Inhaltstyp basiert auf dem Parameter mimetype und dem Zeichensatz (standardmäßig UTF-8).

Antwort- (und Anforderungs-) Objekte werden hier dokumentiert: http://werkzeug.pocoo.org/docs/wrappers/

Simon Sapin
quelle
1
Ist es möglich, diese und andere Optionen auf globaler Ebene festzulegen (dh: Standard)?
EarthmeLon
10
@earthmeLon, stellt eine Unterklasse von flask.Response, überschreibt das default_mimetypeKlassenattribut, und festgelegt , dass als app.response_class werkzeug.pocoo.org/docs/wrappers/... flask.pocoo.org/docs/api/#flask.Flask.response_class
Simon Sapin
@earthmeLon: Wenn Sie festlegen, app.response_classwie Simon betont , denken Sie daran app.make_response, Ihre Antwortinstanz wie in der Antwort unten angegeben abzurufen .
Martin Geisler
Anfragen mit Browsern oder Postboten funktionieren mit diesem Ansatz einwandfrei, Curl funktioniert jedoch nicht gut mit dem zurückgegebenen Response-Objekt. Curl druckt nur "Gefunden". Mit curl "Inhalt zurückgeben, Statuscode, Header" scheint es besser zu funktionieren.
Fuma
143

So einfach ist das

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

Ich hoffe es hilft

Update: Verwenden Sie diese Methode, da sie sowohl mit Python 2.x als auch mit Python 3.x funktioniert

und zweitens wird auch das Problem mit mehreren Headern beseitigt.

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
Harter Daftary
quelle
15
Die einfachste Lösung. Auf jeden Fall sollte die akzeptierte Antwort sein
Omer Dagan
Es gibt einen Nachteil: Sie können nur Header hinzufügen. Als ich das tat, bekam ich zwei Content-Type-Header als Antwort - Standard einen und fügte einen hinzu.
Omikron
1
@omikron Ich habe die Antwort aktualisiert, versuche die neue Methode, die es funktionieren sollte.
Harte Daftary
47

Ich mag die Antwort von @Simon Sapin und habe sie positiv bewertet. Am Ende nahm ich jedoch einen etwas anderen Weg und schuf meinen eigenen Dekorateur:

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

und benutze es so:

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

Ich denke, das ist etwas bequemer.

Michael Wolf
quelle
3
Wenn Sie sowohl eine Antwort als auch einen Statuscode wie zurückgeben return 'msg', 200, führt dies zu ValueError: Expected bytes. Ändern Sie stattdessen den Dekorator in return Response(*r, content_type='whatever'). Das Tupel wird in Argumente entpackt. Vielen Dank für eine elegante Lösung!
Felix
24

Verwenden Sie die Methode make_response , um eine Antwort mit Ihren Daten zu erhalten. Dann ist die Menge MIME - Typ - Attribut . Geben Sie zum Schluss diese Antwort zurück:

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

Wenn Sie Responsedirekt verwenden, verlieren Sie die Möglichkeit, die Antworten durch Festlegen anzupassen app.response_class. Die make_responseMethode verwendet das app.responses_class, um das Antwortobjekt zu erstellen. Hier können Sie Ihre eigene Klasse erstellen und hinzufügen, dass Ihre Anwendung sie global verwendet:

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  
Marianna Vassallo
quelle
Dies ist im Wesentlichen die von @ SimonSapin akzeptierte Antwort, die neu verpackt wurde.
J0e3gan
@ J0e3gan danke. Ich habe meine Antwort erweitert, um besser zu erklären, warum Verwenden make_responsebesser ist als VerwendenResponse
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
Ryan Liu
quelle
2
Ich denke, diese Antwort ist wichtig, weil sie klar macht, wie man die Header von etwas aus einer render_template ändert.
Ein Hettinger
5

Normalerweise müssen Sie das ResponseObjekt nicht selbst erstellen, da dies make_response()für Sie erledigt wird.

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

Eine weitere Sache, es scheint, dass niemand das erwähnt hat after_this_request, ich möchte etwas sagen:

after_this_request

Führt nach dieser Anforderung eine Funktion aus. Dies ist nützlich, um Antwortobjekte zu ändern. Die Funktion wird an das Antwortobjekt übergeben und muss dasselbe oder ein neues zurückgeben.

Damit wir es schaffen after_this_request, sollte der Code folgendermaßen aussehen:

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>'
lord63. j
quelle
4

Sie können die folgende Methode (python3.6.2) ausprobieren:

Fall eins:

@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

Fall zwei:

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

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

Ich benutze Flask. Und wenn Sie json zurückgeben möchten, können Sie dies schreiben:

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)
zhengGuo
quelle