How to push a flask request context when dispatching a different WSGI application

41 Views Asked by At

I am following https://flask.palletsprojects.com/en/3.0.x/patterns/appdispatch/ to dispatch an arbitrary WSGI application alongside a Flask application

import werkzeug.middleware.dispatcher

import mywsgi
import myflask

myflask.app.wsgi_app = werkzeug.middleware.dispatcher.DispatcherMiddleware(
    mywsgi.app,
    {
        "/flask": myflask.app.wsgi_app,
    },
)

and I need to redirect to a Flask URL from the other WSGI application.

Ideally I'd like to use flask.Flask.url_for() but that requires an active request context to work correctly. Otherwise it would be necessary to configure SERVER_NAME, APPLICATION_ROOT and PREFERRED_URL_SCHEME but that is cumbersome if the application is served from different domains, paths or schemes.

Because I'll be processing an actual request, I believe there must be an easy way to push the information from the WSGI environment into a Flask request context so that myflask.app.url_for() can be naturally used from mywsgi.app internals.

Note the myflask.app instance is already visible from the other WSGI application.

1

There are 1 best solutions below

0
N1ngu On

A solution is to wrap the non-Flask WSGI app with a middleware that processes the environ into a Flask request context with https://flask.palletsprojects.com/en/3.0.x/api/#flask.Flask.request_context

import werkzeug.middleware.dispatcher

import mywsgi
import myflask


FLASKAPP_DISPATCH_PATH = "/flask"


def flask_request_context(app):
    """See https://stackoverflow.com/q/77801890/11715259"""
    def _flask_request_context(environ, start_response):
        with flaskapp.request_context({
            **environ,
            "SCRIPT_NAME": "/".join((
                environ["SCRIPT_NAME"],
                FLASKAPP_DISPATCH_PATH,
            ))
        }):
            return app(environ, start_response)
    return _flask_request_context


myflask.app.wsgi_app = werkzeug.middleware.dispatcher.DispatcherMiddleware(
    flask_request_context(mywsgi.app),
    {
        FLASKAPP_DISPATCH_PATH: myflask.app.wsgi_app,
    },
)

The SCRIPT_NAME information from the WSGI environment must be adapted to the dispatch path, otherwise the request context would look like as if no path dispatching was setup.

A downside is the WSGI environment is processed twice to build two different request objects from different WSGI frameworks.