Closed hrimov closed 2 months ago
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?
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.
It can be tested like this
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:
So, my question is: what could be wrong with the Flask middleware?