首页 > 解决方案 > 缓存还是其他?页面未使用 Flask / nginx 更新

问题描述

我建立了一个使用 Flask、nginx 和 uWSGI 的网站。

该网站需要始终显示最新的信息。我一直在通过更改我的网站的主题来测试它。我通过将十六进制值存储在 JSON 文件中,然后在我的 app.py 首次调用时检索该值来使这个主题工作。每当他们保存配置时,我都会更新全局 theme_colour 变量。然后我将 theme_colour 传递给每个 render_template 并在 HTML 中我有一个包含类似这样的样式标签

h1 {
    color: {{ theme_colour }}
}

我的问题是,当我更新主题时,它应该立即更改所有页面,但事实并非如此。当我在配置页面上更新它时,它会自动重新加载页面并且更改在那里工作,但是当我导航到另一个页面时它使用旧颜色。有时刷新页面会修复它,但随后在页面之间随机交换通常会导致它出于某种原因换回旧颜色。清除缓存并刷新它会将其修复在该页面上,但随后导航到另一个页面并返回它通常会换回旧颜色。

我无法弄清楚这里发生了什么。在我正确托管网站之前,我对主题没有任何问题(之前它只是在开发服务器上)。我试图消除这样的缓存,但显然没有奏效:


server {
        listen 80 default_server;
        server_name mydomain.com www.mydomain.com;

        location / {
                include uwsgi_params;
                uwsgi_pass unix:/home/ubuntu/test/test.sock;
                # kill cache
                sendfile off;
                add_header Last-Modified $date_gmt;
                add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
                if_modified_since off;
                expires off;
                etag off;
                proxy_no_cache 1;
                proxy_cache_bypass 1;
        }

        return 301 https://$server_name$request_uri;
}

server {
        listen 443 ssl default_server; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot#
        server_name mydomain.com www.mydomain.com;

        location / {
                include uwsgi_params;
                uwsgi_pass unix:/home/ubuntu/test/test.sock;
                # kill cache
                sendfile off;
                add_header Last-Modified $date_gmt;
                add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
                if_modified_since off;
                expires off;
                etag off;
                proxy_no_cache 1;
                proxy_cache_bypass 1;
        }
}

每当我发送 GET 请求时,它都会说响应标头包含Cache-Control: no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0,所以我不确定这是否是问题所在。

这是我所有的 theme_colour 代码:

@app.route("/index")
def load_index():
    if check_logged_in(session, 0):  # if user is logged in, doesn't require elevated privileges
        return render_template("index.html", theme_colour=theme_colour)  # logged in
    else:
        return redirect("/login")  # not logged in


@app.route("/config", methods=["POST", "GET"])
def load_config():
    if check_logged_in(session, 2):  # if user is logged in, does require elevated privileges
        if request.method == "POST":  # if user clicks update button
            global theme_colour  # make theme colour accessible to all pages
            config = list(request.form.values())  # get input box values
            save_config(config)  # save values to json
            theme_colour = update_theme()  # find theme colour and update global variable
        return render_template("config.html", theme_colour=theme_colour)
    else:
        return abort(403)  # forbidden if not logged in


def update_theme():  # get current theme colour
    with open("config.json", "r") as json_file:
        data = json.load(json_file)
    theme_colour = data["colour"]
    return theme_colour


theme_colour = update_theme()

我觉得我在这里错过了一些东西。有没有人有任何想法?

谢谢。

标签: pythonnginxflaskuwsgi

解决方案


啊,是的,要跟进@SuperShoot 在评论中所说的话:您不能在大多数 Web 服务器上下文中可靠地使用全局变量。大多数情况下,您将拥有多个处理请求的进程(或至少一个随时可能死亡并重生的进程),并且这些进程之间不会共享全局变量。

为了在请求之间可靠地共享状态,您需要为其使用一些外部存储(除非您可以将状态存储在session- 在这种情况下,它不会在不同的客户端之间共享)。

我建议为此连接Redis,但还有其他选择,例如

  • 文件系统(作为平面文件(例如/tmp/myapp/theme.txtshelve或类似文件)
  • 另一个缓存服务器,例如 Memcache
  • 一个数据库(SQLite,一些其他的 SQL,其他的东西)
  • uWSGI 的缓存子系统(虽然它显然只是 uWSGI)
  • uWSGI 的 SharedArea 子系统(非常低级,不推荐,但它就在那里)

然后的想法是在需要时(或为每个请求)从后端加载共享值。


无论哪种方式,我都非常有信心您可以摆脱 Nginx 中的所有缓存配置 - Nginx 不会自行缓存内容,除非被告知(通过其配置,或者可能通过您的应用程序发送的标头)。


推荐阅读