Como faço para definir cabeçalhos de resposta no Flask?


99

Este é o meu código:

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

No entanto, quando faço uma solicitação do navegador para meu servidor, recebo este erro:

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

Também tentei essa abordagem, definindo os cabeçalhos de resposta "após" a solicitação:

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

Sem dados. Recebo o mesmo erro. Existe uma maneira de apenas definir os cabeçalhos de resposta na função de rota? Algo assim seria o ideal:

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

mas não consigo encontrar uma maneira de fazer isso. Por favor ajude.

EDITAR

se eu enrolar o url com uma solicitação POST assim:

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

Eu recebo esta resposta:

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>

Alguma ideia?

Respostas:


96

Você pode fazer isso facilmente:

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

Observe flask.Response e flask.make_response ()

Mas algo me diz que você tem outro problema, porque também after_requestdeveria ter tratado corretamente.

EDITAR
Acabei de notar que você já está usando, o make_responseque é uma das formas de se fazer. Como eu disse antes, after_requestdeveria ter funcionado bem. Tente atingir o ponto final via curl e ver quais são os cabeçalhos:

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

Você deveria 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 o cabeçalho Access-Control-Allow-Origin.

EDIT 2
Como eu suspeitava, você está recebendo 500, então não está definindo o cabeçalho como pensava. Tente adicionar app.debug = Trueantes de iniciar o aplicativo e tente novamente. Você deve obter alguma saída mostrando a causa raiz do problema.

Por exemplo:

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

Fornece uma página de erro html bem formatada, com isso na parte inferior (útil para o 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

Da documentação do frasco ,

flask.make_response (* args)

Às vezes, é necessário definir cabeçalhos adicionais em uma exibição. Como as visualizações não precisam retornar objetos de resposta, mas podem retornar um valor que é convertido em um objeto de resposta pelo próprio Flask, torna-se complicado adicionar cabeçalhos a ele. Esta função pode ser chamada em vez de usar um retorno e você obterá um objeto de resposta que pode ser usado para anexar cabeçalhos.


Você pode enviar as solicitações em args: flask.pocoo.org/docs/0.10/api/#flask.Flask.make_response
tokland

5

Este trabalho para mim

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
Há também a notação return Response(headers={'Access-Control-Allow-Origin':'*'})que me parece mais limpa.
Hermann,

4

Foi assim que adicionei meus cabeçalhos em meu aplicativo de frasco e funcionou perfeitamente

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

0

Podemos definir os cabeçalhos de resposta no aplicativo Python Flask usando o contexto do aplicativo Flask usando flask.g

Esta maneira de definir cabeçalhos de resposta no contexto do aplicativo Flask flask.gé thread-safe e pode ser usada para definir atributos personalizados e dinâmicos de qualquer arquivo do aplicativo. Isso é especialmente útil se estivermos definindo cabeçalhos de resposta personalizados / dinâmicos de qualquer classe auxiliar, que pode também pode ser acessado de qualquer outro arquivo (digamos, middleware, etc), isso flask.gé global e válido apenas para esse segmento de solicitação.

Diga se eu quero ler o cabeçalho de resposta de outra chamada api / http que está sendo chamada a partir deste aplicativo e, em seguida, extrair e definir como cabeçalhos de resposta para este aplicativo.

Código de amostra: arquivo: 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)

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

Chamando o middleware da classe principal

Arquivo : 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)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.