Python Flask, как установить тип контента

176

Я использую Flask и возвращаю XML-файл из запроса get. Как мне установить тип контента на xml?

например

@app.route('/ajax_ddl')
def ajax_ddl():
    xml = 'foo'
    header("Content-type: text/xml")
    return xml
Tampa
источник

Ответы:

255

Попробуйте вот так:

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

Фактический Content-Type основан на параметре mimetype и кодировке (по умолчанию UTF-8).

Объекты ответа (и запроса) описаны здесь: http://werkzeug.pocoo.org/docs/wrappers/

Саймон Сапин
источник
1
Можно ли установить эти и другие параметры на глобальном уровне (т.е. по умолчанию)?
earthmeLon
10
@earthmeLon, создайте подкласс flask.Response, переопределите default_mimetypeатрибут класса и установите его как app.response_class werkzeug.pocoo.org/docs/wrappers/… flask.pocoo.org/docs/api/#flask.Flask.response_class
Саймон Сапин,
@earthmeLon: Если вы установили, app.response_classкак указывает Саймон, не забудьте использовать, app.make_responseчтобы получить свой экземпляр ответа, как указано в ответе ниже .
Мартин Гайслер,
Запросы с браузерами или почтальоном хорошо работают с этим подходом, однако curl плохо работает с возвращенным объектом Response. Скручиваемость просто напечатает «Найдено». С curl "вернуть содержимое, код_состояния, заголовок", кажется, работает лучше.
Фума
144

Так просто, как это

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

Надеюсь, поможет

Обновление: используйте этот метод, потому что он будет работать как с python 2.x, так и с python 3.x

и во-вторых, это также устраняет проблему множественных заголовков.

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
Самое простое решение. Определенно должен быть принят ответ
Омер Даган
Есть недостаток: он позволяет добавлять только заголовки. Когда я это сделал, я получил два заголовка Content-Type в ответ - по умолчанию один и добавил один.
omikron
1
@omikron Я обновил ответ, попробуйте новый метод, он должен работать.
Суровый
48

Мне нравится и проголосовал ответ @Simon Sapin. Однако в итоге я взял немного другую тактику и создал свой собственный декоратор:

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

и использовать его таким образом:

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

Я думаю, что это немного удобнее.

Майкл Вольф
источник
3
При возврате ответа и кода состояния, например return 'msg', 200, это приведет к ValueError: Expected bytes. Вместо этого измените декоратор на return Response(*r, content_type='whatever'). Распакует кортеж с аргументами. Спасибо за элегантное решение!
Феликс
24

Используйте метод make_response, чтобы получить ответ с вашими данными. Затем установите атрибут mimetype . Наконец верните этот ответ:

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

Если вы используете Responseнапрямую, вы теряете возможность настроить ответы, установив app.response_class. make_responseМетод использует , app.responses_classчтобы сделать объект ответа. В этом вы можете создать свой собственный класс, добавив, что ваше приложение использует его глобально:

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  
Марианна Вассалло
источник
По сути, это принятый ответ @ SimonSapin переупакован.
J0e3gan
@ J0e3gan спасибо. Я расширил свой ответ, чтобы лучше объяснить, почему использовать make_responseлучше, чем использоватьResponse
Марианна Вассалло
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
Я думаю, что этот ответ важен, потому что он разъясняет, как изменить заголовки чего-либо из render_template.
Хеттингер
5

Обычно вам не нужно создавать Responseобъект самостоятельно, потому make_response()что позаботится об этом за вас.

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

Еще одна вещь, кажется, что никто не упомянул after_this_request, я хочу кое-что сказать:

after_this_request

Выполняет функцию после этого запроса. Это полезно для изменения объектов ответа. Функция передается объекту ответа и должна возвращать тот же или новый.

так что мы можем сделать это after_this_request, код должен выглядеть следующим образом:

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
источник
4

Вы можете попробовать следующий метод (python3.6.2):

первый случай:

@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

Случай два:

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

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

Я использую Flask. И если вы хотите вернуть json, вы можете написать это:

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
источник