Handler `before_request` doesn't work as expected.
hrimov opened this issue · 0 comments
hrimov commented
I want to implement CORS processing without any third party libraries (like flask-cors). My desire is simple: assign multiple headers to any response, access and process the pre-flight OPTIONS request.
class CORSMiddleware:
def before_request(self):
if request.method == "OPTIONS":
response = jsonify({"status": "ok"})
return self.process_response(response)
def after_request(self, response):
return self.process_response(response)
# noinspection PyMethodMayBeStatic
def process_response(self, response):
if response:
response.headers.add("Access-Control-Allow-Origin", "*")
response.headers.add("Access-Control-Allow-Headers", "Content-Type, Authorization")
response.headers.add("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE, PUT")
return response
def register(self, app: Flask):
app.before_request(self.before_request)
app.after_request(self.after_request)
It can be tested like this
# Note: helper function to reduce view logic
def add_cors_headers(response):
response.headers.add("Access-Control-Allow-Origin", "*")
response.headers.add("Access-Control-Allow-Headers", "Content-Type,Authorization")
response.headers.add("Access-Control-Allow-Methods", "GET,POST,OPTIONS,DELETE,PUT")
return response
user_blueprint = Blueprint("user", __name__, url_prefix="/users")
@user_blueprint.route("/signup", methods=["POST", "OPTIONS"])
def create_user_handler():
# Note: uncomment me to see a desired behaviour
# if request.method == "OPTIONS":
# response = jsonify({"status": "ok"})
# return add_cors_headers(response)
# response = jsonify({"message": "registered"})
# return add_cors_headers(response)
return {"message": "registered"}
def create_app() -> Flask:
app = Flask(__name__)
app.register_blueprint(user_blueprint)
# Note: comment me to see a desired behaviour
CORSMiddleware().register(app)
return app
if __name__ == "__main__":
app = create_app()
app.run(host="127.0.0.1", port=5000, debug=True
With the middleware, it handles a preflight OPTIONS request as an original one:
But the desired behaviour should be like that (you can comment middleware registration and uncomment logic in the view-handler):
Also, I was able to implement desired functionality with the middleware, but with the Werkzeug one:
from werkzeug.wrappers import Request, Response
class CORSMiddleware:
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
request_ = Request(environ)
if request_.method == "OPTIONS":
response = Response(status=200)
response = self.process_response(response)
return response(environ, start_response)
def custom_start_response(status, headers, exc_info=None):
response_headers = self.process_headers(headers)
return start_response(status, response_headers, exc_info)
return self.app(environ, custom_start_response)
def process_response(self, response):
response.headers.add("Access-Control-Allow-Origin", "*")
response.headers.add("Access-Control-Allow-Headers",
"Content-Type, Authorization")
response.headers.add("Access-Control-Allow-Methods",
"GET, POST, OPTIONS, DELETE, PUT")
return response
def process_headers(self, headers):
headers.append(("Access-Control-Allow-Origin", "*"))
headers.append(("Access-Control-Allow-Headers", "Content-Type, Authorization"))
headers.append(
("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE, PUT"))
return headers
# and registering it like that
def create_app() -> Flask:
app = Flask(__name__)
app.register_blueprint(user_blueprint)
app.wsgi_app = CORSMiddleware(app.wsgi_app)
return app
So, my question is: what could be wrong with the Flask middleware?