¿Cómo configuro encabezados de respuesta en Flask?


98

Este es mi codigo:

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

Sin embargo, cuando hago una solicitud desde el navegador a mi servidor, aparece este error:

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

También probé este enfoque, estableciendo los encabezados de respuesta "después" de la solicitud:

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

No dados. Me sale el mismo error. ¿Hay alguna forma de configurar los encabezados de respuesta en la función de ruta? Algo como esto sería ideal:

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

pero no puedo encontrar de todos modos para hacer esto. Por favor ayuda.

EDITAR

si rizo la URL con una solicitud POST como esta:

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

Recibo esta respuesta:

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>

¿Algunas ideas?

Respuestas:


96

Puedes hacer esto con bastante facilidad:

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

Mira flask.Response y flask.make_response ()

Pero algo me dice que tienes otro problema, porque también after_requestdebería haberlo manejado correctamente.

EDITAR
Acabo de notar que ya estás usando make_responsecuál es una de las formas de hacerlo. Como dije antes, after_requestdebería haber funcionado también. Intente llegar al punto final a través de curl y vea cuáles son los encabezados:

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

Deberías ver

> 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

Observando el encabezado Access-Control-Allow-Origin.

EDITAR 2
Como sospechaba, está obteniendo un 500, por lo que no está configurando el encabezado como pensaba. Intente agregar app.debug = Trueantes de iniciar la aplicación y vuelva a intentarlo. Debería obtener algún resultado que le muestre la causa raíz del problema.

Por ejemplo:

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

Da una página de error html muy bien formateada, con esto en la parte inferior (útil para el comando 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

Uso make_responsede Flask algo como

@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

De los documentos del matraz ,

flask.make_response (* argumentos)

A veces es necesario establecer encabezados adicionales en una vista. Debido a que las vistas no tienen que devolver objetos de respuesta, pero pueden devolver un valor que el propio Flask convierte en un objeto de respuesta, resulta complicado agregarle encabezados. Esta función se puede llamar en lugar de usar una devolución y obtendrá un objeto de respuesta que puede usar para adjuntar encabezados.


Puede enviar las solicitudes en los argumentos
tokland

5

Esto funciona para mi

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
También está la notación return Response(headers={'Access-Control-Allow-Origin':'*'})que me parece más limpia.
Hermann

4

Así fue como agregué mis encabezados en mi aplicación de matraz y funcionó perfectamente

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

0

Podemos configurar los encabezados de respuesta en la aplicación Python Flask usando el contexto de la aplicación Flask usando flask.g

Esta forma de configurar los encabezados de respuesta en el contexto de la aplicación Flask flask.ges segura para subprocesos y se puede usar para configurar atributos personalizados y dinámicos desde cualquier archivo de aplicación, esto es especialmente útil si estamos configurando encabezados de respuesta personalizados / dinámicos de cualquier clase auxiliar, que puede también se puede acceder desde cualquier otro archivo (por ejemplo, middleware, etc.), esto flask.ges global y válido solo para ese hilo de solicitud.

Diga si quiero leer el encabezado de respuesta de otra llamada api / http que se está llamando desde esta aplicación, y luego extraiga cualquiera y configúrelo como encabezados de respuesta para esta aplicación.

Código de muestra: archivo: 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)

expediente: 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)

Llamar al middleware desde la clase principal

expediente : 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)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.