Wie setze ich Antwortheader in Flask?

98

Das ist mein Code:

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

Wenn ich jedoch eine Anfrage vom Browser an meinen Server stelle, wird folgende Fehlermeldung angezeigt:

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

Ich habe auch diesen Ansatz ausprobiert und die Antwortheader "nach" der Anfrage gesetzt:

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

Kein Würfel. Ich bekomme den gleichen Fehler. Gibt es eine Möglichkeit, nur die Antwortheader in der Routenfunktion festzulegen? So etwas wäre ideal:

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

aber ich kann es sowieso nicht finden. Bitte helfen Sie.

BEARBEITEN

Wenn ich die URL mit einer POST-Anfrage wie folgt kräusele:

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

Ich bekomme diese Antwort:

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>

Irgendwelche Ideen?

Dopatraman
quelle

Antworten:

96

Sie können dies ziemlich einfach tun:

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

Schauen Sie sich flask.Response und flask.make_response () an.

Aber irgendetwas sagt mir, dass Sie ein anderes Problem haben, weil das after_requestauch richtig hätte gehandhabt werden sollen.

BEARBEITEN
Ich habe gerade bemerkt, dass Sie bereits verwenden, make_responsewas eine der Möglichkeiten ist, dies zu tun. Wie ich schon sagte, after_requesthätte auch funktionieren sollen. Versuchen Sie, den Endpunkt über Curl zu treffen, und sehen Sie, wie die Überschriften lauten:

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

Das solltest du sehen

> 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

Beachten Sie den Header Access-Control-Allow-Origin.

BEARBEITEN 2
Wie ich vermutet habe, erhalten Sie eine 500, sodass Sie den Header nicht so einstellen, wie Sie gedacht haben. Versuchen Sie es hinzuzufügen, app.debug = Truebevor Sie die App starten, und versuchen Sie es erneut. Sie sollten eine Ausgabe erhalten, die Ihnen die Hauptursache des Problems zeigt.

Beispielsweise:

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

Gibt eine schön formatierte HTML-Fehlerseite mit dieser unten (hilfreich für den Befehl 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
quelle
24

Verwendung make_responsevon Flask so etwas wie

@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

Aus Kolbendokumenten ,

flask.make_response (* args)

Manchmal ist es notwendig, zusätzliche Header in einer Ansicht festzulegen. Da Ansichten keine Antwortobjekte zurückgeben müssen, sondern einen Wert zurückgeben können, der von Flask selbst in ein Antwortobjekt konvertiert wird, ist es schwierig, Header hinzuzufügen. Diese Funktion kann aufgerufen werden, anstatt eine Rückgabe zu verwenden, und Sie erhalten ein Antwortobjekt, mit dem Sie Header anhängen können.

Devi
quelle
Sie können die Anfragen in den Argumenten
tokland
5

Diese Arbeit für mich

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()
Deutscher Lopez
quelle
2
Es gibt auch die Notation, return Response(headers={'Access-Control-Allow-Origin':'*'})die für mich sauberer aussieht.
Hermann
4

So wurden meine Header in meine Kolbenanwendung eingefügt und es funktionierte perfekt

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

Wir können die Antwortheader in der Python Flask-Anwendung mithilfe des Flask-Anwendungskontexts mithilfe von festlegen flask.g

Diese Methode zum Festlegen von Antwortheadern im Kontext der Flask-Anwendung flask.gist threadsicher und kann zum Festlegen benutzerdefinierter und dynamischer Attribute aus einer beliebigen Anwendungsdatei verwendet werden. Dies ist besonders hilfreich, wenn Sie benutzerdefinierte / dynamische Antwortheader aus einer beliebigen Hilfsklasse festlegen Der Zugriff erfolgt auch über eine andere Datei (z. B. Middleware usw.). Dies flask.gist global und nur für diesen Anforderungsthread gültig.

Sagen Sie, wenn ich den Antwortheader von einem anderen API / http-Aufruf lesen möchte, der von dieser App aufgerufen wird, und extrahieren Sie dann einen beliebigen & legen Sie ihn als Antwortheader für diese App fest.

Beispielcode: Datei: 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)

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

Aufruf der Middleware aus der Hauptklasse

Datei : 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
quelle