Open In App

Flask WSGI Middleware

Last Updated : 27 Mar, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

When building Flask applications, middleware helps modify requests and responses before they reach the application or the client. Flask itself supports middleware using hooks like before_request and after_request, but WSGI (Web Server Gateway Interface) middleware works at a lower level. It sits between the web server and the application, intercepting and modifying requests and responses before they reach Flask.

This allows us to add features without modifying the Flask app itself, some of the features are:

  • Logging
  • Authentication
  • Compression

How to Implement WSGI Middleware

WSGI middleware follows a specific pattern:

  • It is implemented as a class that takes the Flask app as an argument.
  • The class must define a __call__ method, which processes the WSGI environment (incoming request details) and start_response (the response handler).
  • The modified request is then passed to the Flask app.

Let's look at the Syntax to create and apply WSGI middleware to a flask app.

class CustomWSGIMiddleware:
def __init__(self, app):
self.app = app # Wraps the Flask app

def __call__(self, environ, start_response):
# Modify request before passing it to Flask
print(f"Incoming request: {environ['REQUEST_METHOD']} {environ['PATH_INFO']}")

# Process the request with the Flask app
response = self.app(environ, start_response)

# Modify response if needed
return response

Now, to apply the above WSGI Middleware to a flask app use this:

app.wsgi_app = CustomWSGIMiddleware(app.wsgi_app)

Let's create some basic Flask applications using WSGI Middleware to get a better and understanding.

Creating Custom WSGI Middleware

A simple WSGI middleware is a Python class that wraps around the Flask app and modifies requests or responses. Let's create a basic flask app and implement a custom wsgi middleware in it:

Python
class WSGILoggingMiddleware:
    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        print(f"Incoming request: {environ['REQUEST_METHOD']} {environ['PATH_INFO']}")
        return self.app(environ, start_response)

from flask import Flask

app = Flask(__name__)
app.wsgi_app = WSGILoggingMiddleware(app.wsgi_app)  # Applying WSGI middleware

@app.route('/')
def home():
    return "Hello, WSGI Middleware!"

if __name__ == '__main__':
    app.run(debug=True)

Explanation:

__call__: This method intercepts the request before it reaches Flask.

environ: Contains request details like method and path.

start_response: Used to pass the response back to the WSGI server.

app.wsgi_app = WSGILoggingMiddleware(app.wsgi_app): Applies the middleware to Flask.

Output:

Run the application using command "python app.py" and the request details will be logged in the terminal. Below is the snapshot.

wsgi1
Request details in terminal

Using Third-Party WSGI Middleware

Instead of writing custom middleware, you can use pre-built WSGI middleware. A popular option is Werkzeug’s ProxyFix, which helps handle reverse proxy headers (like Nginx or a load balancer). Reverse proxies often modify headers like REMOTE_ADDR, HTTP_HOST, and SCRIPT_NAME, which Flask wouldn't recognize correctly by default.

Python
from werkzeug.middleware.proxy_fix import ProxyFix
from flask import Flask

app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_port=1, x_prefix=1)

@app.route('/')
def home():
    return "ProxyFix Middleware Applied!"

if __name__ == '__main__':
    app.run(debug=True)

Explanation:

  • ProxyFix(app.wsgi_app, x_for=1, x_host=1):
    • x_for=1 tells Flask to trust the first X-Forwarded-For header, which contains the client’s actual IP.
    • x_host=1 ensures Flask uses the X-Forwarded-Host header to determine the correct host.
  • The middleware fixes incorrect request metadata when Flask is behind a reverse proxy.

Demonstation:

Start the app server using "python app.py" command in the terminal and then open postman and make a GET Request to the URL - "http://127.0.0.1:5000/". It will show the default client IP (localhost), as there are no proxy headers. Below is the snapshot-

wsgi2
Status- 200 OK

Now add the following header to simulate a proxy an make GET Reques to the same URL-

  • Key: X-Forwarded-For
  • Value: 203.0.113.5

Flask will correctly recognize the forwarded IP as the client’s IP-

wsgi3
Proxy IP

Next Article
Article Tags :
Practice Tags :

Similar Reads