Jak ustawić nagłówki odpowiedzi w Flask?

105

To jest mój kod:

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

Jednak kiedy wysyłam żądanie z przeglądarki do mojego serwera, pojawia się ten błąd:

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

Próbowałem też tego podejścia, ustawiając nagłówki odpowiedzi „po” żądaniu:

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

Nie ma kości. Otrzymuję ten sam błąd. Czy istnieje sposób, aby po prostu ustawić nagłówki odpowiedzi w funkcji trasy? Coś takiego byłoby idealne:

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

ale i tak nie mogę tego znaleźć. Proszę pomóż.

EDYTOWAĆ

jeśli zwijam adres URL z żądaniem POST w ten sposób:

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

Otrzymuję tę odpowiedź:

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>

Jakieś pomysły?

dopatraman
źródło

Odpowiedzi:

101

Możesz to zrobić dość łatwo:

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

Spójrz na flask.Response i flask.make_response ()

Ale coś mi mówi, że masz inny problem, ponieważ też after_requestpowinniśmy byli go poprawnie załatwić .

EDYCJA
Zauważyłem, że już używasz, make_responseco jest jednym ze sposobów na zrobienie tego. Jak powiedziałem wcześniej, również after_requestpowinienem zadziałać. Spróbuj trafić w punkt końcowy za pomocą curl i zobacz, jakie są nagłówki:

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

Powinieneś zobaczyć

> 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

Zwracając uwagę na nagłówek Access-Control-Allow-Origin.

EDYCJA 2
Tak jak podejrzewałem, dostajesz 500, więc nie ustawiasz nagłówka tak, jak myślałeś. Spróbuj dodać app.debug = Trueprzed uruchomieniem aplikacji i spróbuj ponownie. Powinieneś otrzymać dane wyjściowe pokazujące główną przyczynę problemu.

Na przykład:

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

Daje ładnie sformatowaną stronę błędu HTML, z tym na dole (przydatne w przypadku polecenia 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
źródło
27

Użyj make_responseczegoś w rodzaju Flask

@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

Z dokumentów Flask ,

flask.make_response (* args)

Czasami konieczne jest ustawienie dodatkowych nagłówków w widoku. Ponieważ widoki nie muszą zwracać obiektów odpowiedzi, ale mogą zwracać wartość, która jest konwertowana na obiekt odpowiedzi przez samą Flask, trudno jest dodać do niego nagłówki. Tę funkcję można wywołać zamiast zwracania, a otrzymasz obiekt odpowiedzi, którego możesz użyć do dołączenia nagłówków.

Devi
źródło
Żądania można przesyłać w args: flask.pocoo.org/docs/0.10/api/#flask.Flask.make_response
tokland,
6

Ta praca dla mnie

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()
Niemiecki Lopez
źródło
3
Jest też zapis, return Response(headers={'Access-Control-Allow-Origin':'*'})który wydaje mi się czystszy.
Hermann
5

W ten sposób dodano moje nagłówki w mojej aplikacji kolby i działało idealnie

@app.after_request
def add_header(response):
    response.headers['X-Content-Type-Options'] = 'nosniff'
    return response
Cole.E
źródło
0

Możemy ustawić nagłówki odpowiedzi w aplikacji Python Flask używając kontekstu aplikacji Flask używając flask.g

Ten sposób ustawiania nagłówków odpowiedzi w kontekście aplikacji Flask flask.gjest bezpieczny dla wątków i może być używany do ustawiania niestandardowych i dynamicznych atrybutów z dowolnego pliku aplikacji, jest to szczególnie przydatne, jeśli ustawiamy niestandardowe / dynamiczne nagłówki odpowiedzi z dowolnej klasy pomocniczej, która może można również uzyskać dostęp z dowolnego innego pliku (na przykład oprogramowania pośredniego itp.), flask.gJest to globalne i ważne tylko dla tego wątku żądania.

Powiedz, czy chcę odczytać nagłówek odpowiedzi z innego wywołania interfejsu API / http, które jest wywoływane z tej aplikacji, a następnie wyodrębnij dowolne i ustaw je jako nagłówki odpowiedzi dla tej aplikacji.

Przykładowy kod: plik: 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)

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

Wywołanie oprogramowania pośredniczącego z klasy głównej

plik: 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
źródło