Comment définir les en-têtes de réponse dans Flask?

99

Voici mon code:

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

Cependant, lorsque je fais une demande du navigateur à mon serveur, j'obtiens cette erreur:

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

J'ai également essayé cette approche, en définissant les en-têtes de réponse "après" la requête:

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

Pas de dé. J'ai la même erreur. Existe-t-il un moyen de définir simplement les en-têtes de réponse dans la fonction d'itinéraire? Quelque chose comme ça serait idéal:

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

mais je ne peux pas trouver de toute façon faire cela. Veuillez aider.

ÉDITER

si je curl l'url avec une requête POST comme ceci:

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

J'obtiens cette réponse:

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>

Des idées?

dopatraman
la source

Réponses:

96

Vous pouvez le faire assez facilement:

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

Regardez flask.Response et flask.make_response ()

Mais quelque chose me dit que vous avez un autre problème, car ils after_requestauraient dû le gérer correctement aussi.

EDIT
Je viens de remarquer que vous utilisez déjà make_responsece qui est l'une des façons de le faire. Comme je l'ai déjà dit, cela after_requestaurait dû fonctionner aussi. Essayez d'atteindre le point de terminaison via curl et voyez quels sont les en-têtes:

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

Tu devrais voir

> 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

Notant l'en-tête Access-Control-Allow-Origin.

EDIT 2
Comme je le soupçonnais, vous obtenez un 500 donc vous ne définissez pas l'en-tête comme vous le pensiez. Essayez d'ajouterapp.debug = True avant de démarrer l'application et réessayez. Vous devriez obtenir une sortie vous montrant la cause première du problème.

Par exemple:

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

Donne une page d'erreur html joliment formatée, avec ceci en bas (utile pour la commande 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
sberry
la source
24

Utilisation make_responsede Flask quelque chose comme

@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

À partir de la documentation Flask ,

flask.make_response (* args)

Parfois, il est nécessaire de définir des en-têtes supplémentaires dans une vue. Étant donné que les vues n'ont pas à renvoyer d'objets de réponse, mais peuvent renvoyer une valeur qui est convertie en objet de réponse par Flask lui-même, il devient difficile d'y ajouter des en-têtes. Cette fonction peut être appelée au lieu d'utiliser un retour et vous obtiendrez un objet de réponse que vous pourrez utiliser pour attacher des en-têtes.

Devi
la source
Vous pouvez envoyer les requêtes dans les arguments
tokland
5

Ce travail pour moi

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()
Allemand Lopez
la source
2
Il y a aussi la notation return Response(headers={'Access-Control-Allow-Origin':'*'})qui me paraît plus propre.
Hermann le
4

C'est ainsi que j'ai ajouté mes en-têtes dans mon application flask et cela a parfaitement fonctionné

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

Nous pouvons définir les en-têtes de réponse dans l'application Python Flask à l'aide du contexte d'application Flask en utilisant flask.g

Cette façon de définir les en-têtes de réponse dans le contexte d'application Flask à l'aide flask.gest thread-safe et peut être utilisée pour définir des attributs personnalisés et dynamiques à partir de n'importe quel fichier d'application, cela est particulièrement utile si nous définissons des en-têtes de réponse personnalisés / dynamiques à partir de n'importe quelle classe d'assistance, qui peut également accessible à partir de tout autre fichier (par exemple, middleware, etc.), flask.gc'est global et valide pour ce thread de requête uniquement.

Dites si je veux lire l'en-tête de réponse d'un autre appel api / http qui est appelé à partir de cette application, puis extrayez-le et définissez-le comme en-tête de réponse pour cette application.

Exemple de code: fichier: 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)

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

Appel du middleware depuis la classe principale

fichier : 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)
src3369
la source