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

Content-Type จริงขึ้นอยู่กับพารามิเตอร์ mimetype และชุดอักขระ (ค่าเริ่มต้นเป็น UTF-8)

วัตถุการตอบสนอง (และคำขอ) ได้รับการบันทึกไว้ที่นี่: http://werkzeug.pocoo.org/docs/wrappers/


1
เป็นไปได้ไหมที่จะตั้งค่าตัวเลือกเหล่านี้และตัวเลือกอื่น ๆ ในระดับโลก (เช่น: ค่าเริ่มต้น)
earthmeLon

10
@earthmeLon สร้างคลาสย่อยflask.Responseแทนที่เขียนทับdefault_mimetypeแอตทริบิวต์ class และตั้งค่าเป็นapp.response_class werkzeug.pocoo.org/docs/wrappers/… flask.pocoo.org/docs/api/#flask.Flask.raskonsejo
Simon Sapin

@earthmeLon: ถ้าคุณตั้งค่าapp.response_classเช่นไซมอนชี้ให้เห็นจำที่จะใช้app.make_responseจะได้รับเช่นการตอบสนองของคุณเช่นการชี้ในคำตอบดังต่อไปนี้
Martin Geisler

คำขอกับเบราว์เซอร์หรือบุรุษไปรษณีย์ทำงานได้ดีกับวิธีการนี้ แต่ขดไม่ทำงานกับวัตถุตอบกลับ Curl จะพิมพ์ "พบ" ด้วย curl "เนื้อหาที่ส่งคืน status_code ส่วนหัว" ดูเหมือนจะทำงานได้ดีขึ้น
fuma

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
ทางออกที่ง่ายที่สุด ควรเป็นคำตอบที่แน่นอน
Omer Dagan

มีข้อเสียเปรียบ: มันช่วยให้คุณเพิ่มส่วนหัวเท่านั้น เมื่อฉันทำฉันลงเอยด้วยส่วนหัวของ Content-Type สองแบบ - หนึ่งค่าเริ่มต้นและเพิ่มหนึ่งส่วน
omikron

1
@omikron ฉันได้อัปเดตคำตอบแล้วลองวิธีการใหม่ที่ควรใช้
Harsh Daftary

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')มันจะแกะ tuple เพื่อหาข้อโต้แย้ง ขอบคุณสำหรับวิธีการแก้ปัญหาที่สง่างาม!
เฟลิกซ์

24

ใช้เมธอด make_responseเพื่อรับการตอบกลับกับข้อมูลของคุณ จากนั้นตั้งค่าแอตทริบิวต์ชนิด mime ในที่สุดก็กลับคำตอบนี้:

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

ถ้าคุณใช้โดยตรงที่คุณสูญเสียโอกาสที่จะปรับแต่งการตอบสนองโดยการตั้งค่าResponse วิธีการใช้ที่จะทำให้วัตถุที่ตอบสนอง ในที่นี้คุณสามารถสร้างคลาสของคุณเองเพิ่มทำให้แอปพลิเคชันของคุณใช้ทั่วโลก:app.response_classmake_responseapp.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
Hettinger

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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.