Як встановити заголовки відповідей у ​​Flask?


99

Це мій код:

@app.route('/hello', methods=["POST"])
def hello():
    resp = make_response()
    resp.headers['Access-Control-Allow-Origin'] = '*'
    return resp

Однак, коли я роблю запит від браузера на свій сервер, я отримую таку помилку:

XMLHttpRequest cannot load http://localhost:5000/hello. 
No 'Access-Control-Allow-Origin' header is present on the requested resource.

Я також спробував такий підхід, встановивши заголовки відповідей "після" запиту:

@app.after_request
def add_header(response):
    response.headers['Access-Control-Allow-Origin'] = '*'
    return response

Без кісток. Я отримую ту ж помилку. Чи є спосіб просто встановити заголовки відповідей у ​​функції маршруту? Щось подібне було б ідеально:

@app.route('/hello', methods=["POST"])
    def hello(response): # is this a thing??
        response.headers['Access-Control-Allow-Origin'] = '*'
        return response

але я все одно не можу знайти це. Будь ласка, допоможіть.

EDIT

якщо я скручую URL-адресу із запитом POST приблизно так:

curl -iX POST http://localhost:5000/hello

Я отримую таку відповідь:

HTTP/1.0 500 INTERNAL SERVER ERROR
Content-Type: text/html
Content-Length: 291
Server: Werkzeug/0.9.6 Python/2.7.6
Date: Tue, 16 Sep 2014 03:58:42 GMT

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>500 Internal Server Error</title>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error and was unable to complete your request.  Either the server is overloaded or there is an error in the application.</p>

Якісь ідеї?

Відповіді:


96

Ви можете зробити це досить легко:

@app.route("/")
def home():
    resp = flask.Response("Foo bar baz")
    resp.headers['Access-Control-Allow-Origin'] = '*'
    return resp

Подивіться на flask.Response і flask.make_response ()

Але щось мені підказує, що у вас є інша проблема, тому що теж after_requestслід було б з нею правильно впоратися.

EDIT
Я щойно помітив, що ви вже використовуєте, make_responseщо є одним із способів зробити це. Як я вже говорив раніше, after_requestмав би також працювати. Спробуйте вразити кінцеву точку за допомогою curl і подивіться, що таке заголовки:

curl -i http://127.0.0.1:5000/your/endpoint

Ви повинні побачити

> curl -i 'http://127.0.0.1:5000/'
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 11
Access-Control-Allow-Origin: *
Server: Werkzeug/0.8.3 Python/2.7.5
Date: Tue, 16 Sep 2014 03:47:13 GMT

Відзначаючи заголовок Access-Control-Allow-Origin.

РЕДАКТУВАТИ 2
Як я підозрював, ви отримуєте 500, тож ви не встановлюєте заголовок, як думали. Спробуйте додати, app.debug = Trueперш ніж запускати програму, і повторіть спробу. Ви повинні отримати вихідні дані, що показують вам першопричину проблеми.

Наприклад:

@app.route("/")
def home():
    resp = flask.Response("Foo bar baz")
    user.weapon = boomerang
    resp.headers['Access-Control-Allow-Origin'] = '*'
    return resp

Дає приємно відформатовану сторінку помилок html, з цим внизу (корисно для команди curl)

Traceback (most recent call last):
...
  File "/private/tmp/min.py", line 8, in home
    user.weapon = boomerang
NameError: global name 'boomerang' is not defined

24

Використання make_responseколби щось на зразок

@app.route("/")
def home():
    resp = make_response("hello") #here you could use make_response(render_template(...)) too
    resp.headers['Access-Control-Allow-Origin'] = '*'
    return resp

З колби-документів ,

flask.make_response (* аргументи)

Іноді доводиться встановлювати додаткові заголовки у поданні. Оскільки подання не повинні повертати об'єкти відповіді, але можуть повертати значення, яке перетворюється в об'єкт відповіді самою Flask, додавати заголовки до нього стає складно. Цю функцію можна викликати замість використання return, і ви отримаєте об'єкт відповіді, який можна використовувати для прикріплення заголовків.


Ви можете надіслати запити в аргументах: flask.pocoo.org/docs/0.10/api/#flask.Flask.make_response
Tokland

5

Ця робота для мене

from flask import Flask
from flask import Response

app = Flask(__name__)

@app.route("/")
def home():
    return Response(headers={'Access-Control-Allow-Origin':'*'})

if __name__ == "__main__":
    app.run()

2
Є також позначення, return Response(headers={'Access-Control-Allow-Origin':'*'})яке мені здається чистішим.
Герман

4

Це було те, як додав мої заголовки в мою програму-колбу, і це спрацювало чудово

@app.after_request
def add_header(response):
    response.headers['X-Content-Type-Options'] = 'nosniff'
    return response

0

Ми можемо встановити заголовки відповідей у ​​програмі Python Flask, використовуючи контекст програми Flask flask.g

Цей спосіб встановлення заголовків відповідей у ​​контексті програми Flask flask.gє безпечним для потоків і може використовуватися для встановлення користувацьких та динамічних атрибутів з будь-якого файлу програми, це особливо корисно, якщо ми встановлюємо користувацькі / динамічні заголовки відповідей з будь-якого допоміжного класу, який може доступ до них також можна отримати з будь-якого іншого файлу (скажімо, як проміжне програмне забезпечення тощо), це flask.gє загальнодоступним і діє лише для цього потоку запитів.

Скажімо, якщо я хочу прочитати заголовок відповіді з іншого виклику api / http, який викликається з цієї програми, а потім витягнути будь-який і встановити його як заголовки відповідей для цього додатка.

Зразок коду: файл: helper.py

import flask
from flask import request, g
from multidict import CIMultiDict
from asyncio import TimeoutError as HttpTimeout
from aiohttp import ClientSession

    def _extract_response_header(response)
      """
      extracts response headers from response object 
      and stores that required response header in flask.g app context
      """
      headers = CIMultiDict(response.headers)
      if 'my_response_header' not in g:
        g.my_response_header= {}
        g.my_response_header['x-custom-header'] = headers['x-custom-header']


    async def call_post_api(post_body):
      """
      sample method to make post api call using aiohttp clientsession
      """
      try:
        async with ClientSession() as session:
          async with session.post(uri, headers=_headers, json=post_body) as response:
            responseResult = await response.read()
            _extract_headers(response, responseResult)
            response_text = await response.text()
      except (HttpTimeout, ConnectionError) as ex:
        raise HttpTimeout(exception_message)

файл: middleware.py

import flask
from flask import request, g

class SimpleMiddleWare(object):
    """
    Simple WSGI middleware
    """

    def __init__(self, app):
        self.app = app
        self._header_name = "any_request_header"

    def __call__(self, environ, start_response):
        """
        middleware to capture request header from incoming http request
        """
        request_id_header = environ.get(self._header_name)
        environ[self._header_name] = request_id_header

        def new_start_response(status, response_headers, exc_info=None):
            """
            set custom response headers
            """
            # set the request header as response header
            response_headers.append((self._header_name, request_id_header))
            # this is trying to access flask.g values set in helper class & set that as response header
            values = g.get(my_response_header, {})
            if values.get('x-custom-header'):
                response_headers.append(('x-custom-header', values.get('x-custom-header')))
            return start_response(status, response_headers, exc_info)

        return self.app(environ, new_start_response)

Виклик проміжного програмного забезпечення з основного класу

файл: main.py

from flask import Flask
import asyncio
from gevent.pywsgi import WSGIServer
from middleware import SimpleMiddleWare

    app = Flask(__name__)
    app.wsgi_app = SimpleMiddleWare(app.wsgi_app)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.