Python Flask, como definir o tipo de conteúdo

176

Estou usando o Flask e retorno um arquivo XML de uma solicitação get. Como defino o tipo de conteúdo para xml?

por exemplo

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

Respostas:

255

Tente assim:

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

O tipo de conteúdo real é baseado no parâmetro mimetype e no conjunto de caracteres (o padrão é UTF-8).

Os objetos de resposta (e solicitação) estão documentados aqui: http://werkzeug.pocoo.org/docs/wrappers/

Simon Sapin
fonte
1
É possível definir essas e outras opções em nível global (por exemplo: padrão)?
earthmeLon
10
@earthmeLon, fazer uma subclasse de flask.Response, substituir o default_mimetypeatributo de classe e defina-o como app.response_class werkzeug.pocoo.org/docs/wrappers/... flask.pocoo.org/docs/api/#flask.Flask.response_class
Simon Sapin
@earthmeLon: Se você definir app.response_classcomo Simon aponta, lembre-se de usar app.make_responsepara obter sua instância de resposta, como indicado na resposta abaixo .
Martin Geisler
Solicitações com navegadores ou carteiro funcionam bem com essa abordagem, no entanto, a ondulação não funciona bem com o objeto de resposta retornado. A onda apenas imprimirá "Encontrado". Com o curl "retornar conteúdo, status_code, header" parece funcionar melhor.
fuma
144

Tão simples como isso

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

Espero que ajude

Atualização: use esse método porque ele funcionará com o python 2.xe python 3.x

e segundo, também elimina o problema de vários cabeçalhos.

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
Harsh Daftary
fonte
15
A solução mais simples. Definitivamente deve ser a resposta aceita
Omer Dagan
Há uma desvantagem: permite apenas ADICIONAR cabeçalhos. Quando o fiz, acabei com dois cabeçalhos de tipo de conteúdo em resposta - o padrão é um e adicionei um.
Omikron
1
@omikron Atualizei a resposta, tente o novo método que deve funcionar.
Harsh Daftary
47

Gosto e votei na resposta de @Simon Sapin. Acabei adotando uma tática um pouco diferente, no entanto, e criei meu próprio decorador:

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 use-o assim:

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

Eu acho que isso é um pouco mais confortável.

Michael Wolf
fonte
3
Ao retornar uma resposta e um código de status como return 'msg', 200, isso levará a ValueError: Expected bytes. Em vez disso, mude o decorador para return Response(*r, content_type='whatever'). Ele descompactará a tupla para argumentos. Obrigado, porém, por uma solução elegante!
Felix
24

Use o método make_response para obter uma resposta com seus dados. Em seguida, defina o atributo mimetype . Por fim, retorne esta resposta:

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

Se você usar Responsediretamente, perderá a chance de personalizar as respostas configurando app.response_class. O make_responsemétodo usa o app.responses_classpara criar o objeto de resposta. Neste você pode criar sua própria classe, adicionar make seu aplicativo usa globalmente:

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
fonte
Esta é essencialmente a resposta aceita do @ SimonSapin reembalada.
J0e3gan
@ J0e3gan obrigado. I têm expandido a minha resposta para explicar melhor por que usar make_responseé melhor do que usarResponse
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
fonte
2
Eu acho que essa resposta é importante porque deixa claro como alterar os cabeçalhos em algo de um render_template.
Um Hettinger
5

Normalmente você não precisa criar o Responseobjeto, porque make_response()ele cuidará disso para você.

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

Mais uma coisa, parece que ninguém mencionou o after_this_request, eu quero dizer uma coisa:

after_this_request

Executa uma função após esta solicitação. Isso é útil para modificar objetos de resposta. A função recebe o objeto de resposta e precisa retornar o mesmo ou um novo.

para que possamos fazê-lo after_this_request, o código deve ficar assim:

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
fonte
4

Você pode tentar o seguinte método (python3.6.2):

caso um:

@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 dois:

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

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

Estou usando o Flask. E se você deseja retornar o json, pode escrever o seguinte:

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
fonte