Как установить заголовки ответов во Flask?


103

Это мой код:

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

Однако когда я делаю запрос из браузера на свой сервер, я получаю эту ошибку:

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

Я тоже пробовал этот подход, установив заголовки ответа «после» запроса:

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

Никаких кубиков. Я получаю ту же ошибку. Есть ли способ просто установить заголовки ответа в функции маршрута? Что-то вроде этого было бы идеально:

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

но я не могу найти способ сделать это. Пожалуйста помоги.

РЕДАКТИРОВАТЬ

если я скручиваю URL-адрес с запросом POST следующим образом:

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

Я получаю такой ответ:

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>

Любые идеи?

Ответы:


98

Вы можете сделать это довольно легко:

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

Посмотрите на flask.Response и flask.make_response ()

Но что-то мне подсказывает, что у вас другая проблема, потому что after_requestони тоже должны были решить ее правильно.

ИЗМЕНИТЬ
Я только что заметил, что вы уже используете, make_responseчто является одним из способов сделать это. Как я уже сказал, after_requestтоже должно было сработать. Попробуйте попасть в конечную точку через curl и посмотрите, что это за заголовки:

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

Тебе следует увидеть

> 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

Обратите внимание на заголовок Access-Control-Allow-Origin.

РЕДАКТИРОВАТЬ 2
Как я и подозревал, вы получаете 500, поэтому вы не устанавливаете заголовок, как вы думали. Попробуйте добавить app.debug = Trueперед запуском приложения и повторите попытку. Вы должны получить какой-то вывод, показывающий основную причину проблемы.

Например:

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

Дает красиво отформатированную страницу ошибок html с этим внизу (полезно для команды 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

25

Использование make_responseFlask что-то вроде

@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

Из документов фляги ,

flask.make_response (* аргументы)

Иногда необходимо установить дополнительные заголовки в представлении. Поскольку представления не должны возвращать объекты ответа, но могут возвращать значение, преобразованное в объект ответа самим Flask, становится сложно добавить к нему заголовки. Эту функцию можно вызвать вместо использования возврата, и вы получите объект ответа, который можно использовать для прикрепления заголовков.


Вы можете отправлять запросы в аргументах: flask.pocoo.org/docs/0.10/api/#flask.Flask.make_response
tokland

5

Эта работа для меня

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
Есть также обозначение, return Response(headers={'Access-Control-Allow-Origin':'*'})которое мне кажется более понятным.
Hermann

4

Вот так я добавлял заголовки в мое фляжное приложение, и он отлично работал

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

0

Мы можем установить заголовки ответов в приложении Python Flask, используя контекст приложения Flask, используя flask.g

Этот способ установки заголовков ответов в контексте приложения Flask flask.gявляется потокобезопасным и может использоваться для установки настраиваемых и динамических атрибутов из любого файла приложения, это особенно полезно, если мы устанавливаем настраиваемые / динамические заголовки ответа из любого вспомогательного класса, который может также можно получить доступ из любого другого файла (например, промежуточного программного обеспечения и т. д.), он flask.gявляется глобальным и действителен только для этого потока запроса.

Скажите, если я хочу прочитать заголовок ответа из другого вызова api / http, который вызывается из этого приложения, а затем извлечь любой и установить его в качестве заголовков ответа для этого приложения.

Пример кода: файл: 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)

файл: 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)

Вызов промежуточного программного обеспечения из основного класса

файл : 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)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.