Python Flask, як встановити тип вмісту


176

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

напр

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

Відповіді:


255

Спробуйте так:

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

Фактичний тип вмісту заснований на параметрі 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
Найпростіше рішення. Однозначно повинна бути прийнята відповідь
Омер Даган

Є і недолік: він дозволяє лише додавати заголовки ADD. Коли я це зробив, я отримав у відповідь два заголовки типу вмісту - один за замовчуванням і додав один.
омікрон

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
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
Я вважаю, що ця відповідь є важливою, оскільки чітко визначає, як змінити заголовки на щось із шаблону 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>'

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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.