Middleware is used to process and modify requests and responses before they reach the application or client. While Flask provides request hooks such as before_request and after_request, WSGI (Web Server Gateway Interface) middleware operates at a lower level between the web server and the Flask application, allowing requests and responses to be intercepted and modified before reaching Flask. Some of the features are:
- Logging
- Authentication
- Compression
Implementation
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.
The following syntax demonstrates how to create and apply WSGI middleware to a Flask application.
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)
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:
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: A callable provided by the WSGI server used to start the HTTP response.
- 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.

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.
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) configures Flask to trust specific proxy headers when the application is deployed behind a reverse proxy.
- x_for=1 allows Flask to use the first X-Forwarded-For header to identify the client’s actual IP address.
- x_host=1 enables Flask to determine the correct host using the X-Forwarded-Host header.
Demonstration
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.

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-
