ChatGPT解决这个技术问题 Extra ChatGPT

Python Flask, how to set content type

I am using Flask and I return an XML file from a get request. How do I set the content type to xml ?

e.g.

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

S
Simon Sapin

Try like this:

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

The actual Content-Type is based on the mimetype parameter and the charset (defaults to UTF-8).

Response (and request) objects are documented here: http://werkzeug.pocoo.org/docs/wrappers/


Is it possible to set these and other options on a global level (ie: default)?
@earthmeLon, make a subclass of flask.Response, override the default_mimetype class attribute, and set that as app.response_class werkzeug.pocoo.org/docs/wrappers/… flask.pocoo.org/docs/api/#flask.Flask.response_class
@earthmeLon: If you set app.response_class like Simon points out, remember to use app.make_response to get your reponse instance like pointed out in the answer below.
Requests with browsers or postman work fine with this approach, however curl does not work well with the returned Response object. Curl will just print "Found". With curl "return content, status_code, header" seem to work better.
l
lmat - Reinstate Monica

As simple as this

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

Hope it helps

Update: Use the method below because it will work with both python 2.x and python 3.x and it eliminates the "multiple header" problem (potentially emitting multiple, duplicate headers).

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

The simplest solution. Definitely should be the accepted answer
There is a drawback: it allows you only ADD headers. When I did it, I ended up with two Content-Type headers in response - default one and added one.
@omikron I have updated the answer, try the new method it should work.
@HarshDaftary it is unclear to me which is the new method and which is the old. Could you please replace "this method" with "the method above" or "the method below"?
@Leo I added the desired clarification.
M
Michael Wolf

I like and upvoted @Simon Sapin's answer. I ended up taking a slightly different tack, however, and created my own decorator:

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

and use it thus:

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

I think this is slightly more comfortable.


When returning both a response and a status code like return 'msg', 200, this will lead to ValueError: Expected bytes. Instead, change the decorator to return Response(*r, content_type='whatever'). It will unpack the tuple to arguments. Thank you though, for an elegant solution!
t
ti7

Use the make_response method to get a response with your data. Then set the mimetype attribute. Finally return this response:

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

If you use Response directly, you lose the chance to customize the responses by setting app.response_class. The make_response method uses the app.responses_class to make the response object. In this you can create your own class, add make your application uses it globally:

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  

This is essentially @SimonSapin's accepted answer repackaged.
@J0e3gan thanks. I have expanded my answer to better explain why using make_response is better than using Response
R
Ryan Liu
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

I think this answer is important because it makes clear how to change the headers on something from a render_template.
z
zhengGuo

You can try the following method(python3.6.2):

case one:

@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

case two:

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

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

I am using Flask .And if you want to return json,you can write this:

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)

l
lord63. j

Usually you don’t have to create the Response object yourself because make_response() will take care of that for you.

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

One more thing, it seems that no one mentioned the after_this_request, I want to say something:

after_this_request

Executes a function after this request. This is useful to modify response objects. The function is passed the response object and has to return the same or a new one.

so we can do it with after_this_request, the code should look like this:

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>'