Flask 登录与 Apache 缓存

Flask login vs. Apache caching

我是一名 Web 开发新手,但经验丰富 python 程序员和 Apache dolt。最近,我一直在摆弄托管一个小型网站,并通过一些托管问题、Flask、html 模板等来学习我的方法

我遵循了几个关于在访问控制端点上使用 @login_required 装饰器控制对页面的访问以及使用 session 存储登录的 k-v 对的 Flask 教程。当 运行 在本地计算机上的 Flask 开发服务器上本地时,这一切都完美无缺。然而,当我将它推送到我的托管服务时,我得到了我认为是许多访问控制端点的缓存行为,并且我能够在注销后看到它们(并检查会话数据以确保密钥已删除)。

一些细节...

我的 passenger_wsgi 文件:

import sys, os
from datetime import timedelta
INTERP = "/home/<website>/venv1/bin/python3"
#INTERP is present twice so that the new Python interpreter knows the actual executable path
if sys.executable != INTERP: os.execl(INTERP, INTERP, *sys.argv)

# def application(environ, start_response):
#     start_response('200 OK', [('Content-type', 'text/plain')])
#     return ["Hello, world!"]

sys.path.append(os.getcwd())
from app import app as application

登录后,一切正常。注销后,我仍然可以访问应该受访问控制的端点,当我在浏览器中检查网络流量时,我反复看到这个“证据”:

Summary
URL: https://<website>/<endpoint>  <---- an endpoint covered by @login_required
Status: 200
Source: Memory Cache

Request
No request, served from the memory cache.

Response
Content-Type: text/html; charset=utf-8
Expires: Wed, 22 Dec 2021 17:14:00 GMT
Date: Wed, 22 Dec 2021 17:04:00 GMT
Content-Length: 23
Cache-Control: max-age=600
Vary: User-Agent
Status: 200 OK
x-powered-by: Phusion Passenger 5.0.30
Server: Apache

所以我的问题是这些...

  1. 我的诊断是否正确,这是 Apache 缓存在起作用吗? (证据看起来很有说服力……:))
  2. 我宁愿不(在这个时候)投入精力转向 flask-login 除非那是治愈性的。
  3. 有没有一种简单的方法可以控制这种行为,而无需成为 apache 或 Passenger 配置文件等方面的专家?如果对于这个低流量站点可行,我不介意关闭缓存,但我会对 好的解决方案 看起来像什么感兴趣,以便自学控制缓存或以某种方式告诉 apache (?) 哪些端点是访问控制的,等等。

我谦虚地向处理这些堆栈的人提出我的问题!

从 5.0 开始,passenger 会“有帮助地”将 cache-control headers 添加到它认为 'cachable'.

的回复中

为了阻止这种情况,您的应用程序 should add the header Cache-Control: no-store

在 Flask 中全局执行此操作 described here:

@app.after_request
def add_header(response):
    # response.cache_control.no_store = True
    if 'Cache-Control' not in response.headers:
        response.headers['Cache-Control'] = 'no-store'
    return response

如果你想更有辨别力并且只想对需要登录的路由执行此操作,你可以对 login_required 装饰器进行自己的扩展以对需要登录的路由执行此操作(或一个完全独立的装饰器)

from flask import make_response
from flask_login import login_required as _login_required

def login_required(f):
    # apply the usual login_required decorator
    decorated = _login_required(f)
    def cache_no_store_login_required_view(*args, **kwargs):
        resp = make_response(decorated(*args, **kwargs))
        # add the cache-control header to the response
        resp.headers['Cache-Control'] = 'no-store'
        return resp
    return cache_no_store_login_required_view

或者作为单独的装饰器来设置no-store...

from functools import wraps
def cache_no_store(f):
    @wraps(f)
    def decorated_view(*args, **kwargs):
        resp = make_response(f(*args, **kwargs))
        resp.headers['Cache-Control'] = 'no-store'

@app.route('/protected')
@cache_no_store
@login_required
def my_route():
    # ...