LaTeX957300 views
中学数学621382 views
高校国語785655 views
中学社会667106 views
中学英語808712 views
教育148875 views
MathPython491378 views
雑学1472593 views
小学算数1194618 views
中学理科1626207 views
Help
Tools

English

Flask のミドルウェア(WSGI middleware)を実装する

Flask は WSGI アプリケーションであり、WSGI ミドルウェアを使ってリクエスト/レスポンスの処理をカスタマイズできる。ミドルウェアはアプリケーションをラップし、前処理・後処理を挟む。

WSGI の基本

WSGI アプリケーションは callable で、environstart_response を受け取る。

def simple_app(environ, start_response):
    status = '200 OK'
    headers = [('Content-Type', 'text/plain')]
    start_response(status, headers)
    return [b'Hello, World!']

Flask アプリも内部的にはこの形式である。

基本的なミドルウェア

class SimpleMiddleware:
    def __init__(self, app):
        self.app = app
    
    def __call__(self, environ, start_response):
        # 前処理
        print(f"Request: {environ['PATH_INFO']}")
        
        # 元のアプリケーションを呼び出す
        return self.app(environ, start_response)

# Flask アプリにミドルウェアを適用
app.wsgi_app = SimpleMiddleware(app.wsgi_app)

app.wsgi_app をラップすることで、Flask のルーティングより前に処理を挟める。

レスポンスを加工するミドルウェア

class ResponseTimeMiddleware:
    def __init__(self, app):
        self.app = app
    
    def __call__(self, environ, start_response):
        import time
        start = time.time()
        
        def custom_start_response(status, headers, exc_info=None):
            elapsed = time.time() - start
            headers.append(('X-Response-Time', f'{elapsed:.3f}s'))
            return start_response(status, headers, exc_info)
        
        return self.app(environ, custom_start_response)

app.wsgi_app = ResponseTimeMiddleware(app.wsgi_app)

IP フィルタリングミドルウェア

class IPFilterMiddleware:
    def __init__(self, app, blocked_ips):
        self.app = app
        self.blocked_ips = blocked_ips
    
    def __call__(self, environ, start_response):
        remote_addr = environ.get('REMOTE_ADDR', '')
        if remote_addr in self.blocked_ips:
            status = '403 Forbidden'
            headers = [('Content-Type', 'text/plain')]
            start_response(status, headers)
            return [b'Access Denied']
        return self.app(environ, start_response)

app.wsgi_app = IPFilterMiddleware(app.wsgi_app, {'192.168.1.100'})

Werkzeug の組み込みミドルウェア

Werkzeug にはいくつかのミドルウェアが用意されている。

from werkzeug.middleware.proxy_fix import ProxyFix
from werkzeug.middleware.profiler import ProfilerMiddleware

# リバースプロキシ対応
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1)

# プロファイリング
app.wsgi_app = ProfilerMiddleware(app.wsgi_app)

ミドルウェア vs before_request

ミドルウェアWSGI レベル、Flask の外側で動作
before_requestFlask レベル、コンテキストが利用可能

ミドルウェアは Flask のコンテキストにアクセスできないが、より低レベルな制御が可能である。単純な前処理・後処理なら before_request/after_request のほうが扱いやすい。

複数ミドルウェアの適用順序

app.wsgi_app = MiddlewareA(app.wsgi_app)
app.wsgi_app = MiddlewareB(app.wsgi_app)

# リクエスト時: B → A → Flask → A → B

最後に適用したミドルウェアが最初に実行される。