You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

部署在Nginx下的Flask应用搜索结果页需刷新才能显示的问题排查

问题描述
  • 基于Flask搭建的网站,本地运行完全正常,部署到VPS通过Nginx提供服务时,搜索操作会跳转至错误页面,但刷新页面(有时需多次)后结果可正常显示。
  • 若直接在VPS上通过gunicorn --bind 0.0.0.0:5000运行应用,访问example.com:5000时功能完全正常。

Nginx错误日志警告

搜索失败时,Nginx错误日志出现如下警告:

2023/05/22 12:23:07 [warn] 994#994: *519 an upstream response is buffered to a temporary file /var/lib/nginx/tmp/proxy/2/00/0000000002 while reading upstream, client: 216.227.60.13, server: , request: "GET /us_news HTTP/1.1", upstream: "http://unix:/home/siteadmin/personal-website/siteapp.sock:/us_news", host: "example.com", referrer: "https://example.com/"

调试核心错误与尝试的解决方法

开启Flask调试模式后发现:访问/news_results路由时出现KeyError: 'states',即session中不存在'states'键,但刷新后该键又存在。

尝试过以下方法,均未解决问题:

  • 在报错代码前添加time.sleep(5)
  • 在Nginx配置中设置proxy_request_buffering off;

相关代码

Flask视图代码

from flask import Blueprint, render_template, redirect, url_for, session, make_response
from flask import current_app as app, Flask, request, jsonify, g
from flask_paginate import Pagination, get_page_args
import json
import psycopg2
import click
from ..dbcon import makeConn
from datetime import datetime


from KnowledgeSchema import schema
from sqlalchemy.orm import Session

def addError(error):
    with Session(schema.engine, expire_on_commit=False) as session:
        session.add(error)
        session.commit()
        # session.close()

# Blueprint Configuration
us_news_bp = Blueprint('us_news_bp', __name__,
                    url_prefix='',
                    template_folder='templates',
                    static_folder='static') 



def getArticles(states, topics, startDate, endDate):
    print(states)
    if states != '%':
        states = '|'.join(states)
    if topics != '%':
        topics = '|'.join(topics)
    search = {'states' : tuple(states), 'topics' : tuple(topics)}
    q = "select count(*) from articles"
    conn = makeConn()
    dict_cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
    dict_cur.execute(q)
    total = dict_cur.fetchone()[0]
    page, per_page, offset = get_page_args(
    page_parameter="p", per_page_parameter="pp", pp=20
    )
    if per_page:
        sqlStr = """
            SELECT title,pubdate,feed_id,articles.url,thumbnails[1],description,state_code,
            keywords, creators, news_outlets.outlet_name,news_outlets.main_url, news_outlets.mbfc_bias,
            news_outlets.mbfc_factual, news_outlets.mbfc_cred, news_outlets.twitter, news_outlets.mbfc_url, news_outlets.facebook, news_outlets.youtube, news_outlets.wikipedia,
            news_feeds.section as section, news_feeds.url AS feedurl, supersection, COUNT(*) OVER() AS num_rows
            FROM articles
            INNER JOIN news_feeds USING (feed_id)
            INNER JOIN states USING (state_id)
            INNER JOIN news_outlets USING (outlet_id)
            WHERE states.state_code SIMILAR TO %s
            AND supersection SIMILAR TO %s
            AND pubdate BETWEEN TO_DATE(%s, 'YYYY-MM-DD') and TO_DATE(%s, 'YYYY-MM-DD')
            ORDER BY pubdate_linux ASC LIMIT {} OFFSET {}
            """
        print(sqlStr)
        sql = dict_cur.mogrify(sqlStr.format(per_page, offset), (states, topics, startDate, endDate))
    else:
        sql = dict_cur.mogrify(
            """
            SELECT title,pubdate,feed_id,articles.url,thumbnails[1],description,state_code,
            keywords, creators, news_outlets.outlet_name,news_outlets.main_url, news_outlets.mbfc_bias,
            news_outlets.mbfc_factual, news_outlets.mbfc_cred, news_outlets.twitter, news_outlets.mbfc_url, news_outlets.facebook, news_outlets.youtube, news_outlets.wikipedia,
            news_feeds.section as section, news_feeds.url AS feedurl, supersection, COUNT(*) OVER() AS num_rows
            FROM articles
            INNER JOIN news_feeds USING (feed_id)
            INNER JOIN states USING (state_id)
            INNER JOIN news_outlets USING (outlet_id)
            WHERE states.state_code SIMILAR TO %s
            AND supersection SIMILAR TO %s
            AND pubdate BETWEEN TO_DATE(%s, 'YYYY-MM-DD') and TO_DATE(%s, 'YYYY-MM-DD'
            ORDER BY pubdate_linux ASC)
        """.format((states, topics, startDate, endDate)))
    print("sql is:", sql)
    print("SqL")
    dict_cur.execute(sql)
    articles = dict_cur.fetchall()
    total = articles[0][-1]
    pagination = get_pagination(
        p=page,
        pp=per_page,
        total=total,
        format_total=True,
        format_number=True,
        page_parameter="p",
        per_page_parameter="pp",
    )
    return articles, pagination


@us_news_bp.route('/us_news', methods=['GET', 'POST'])
def us_news():
  if request.method == 'POST':
    states = request.form.getlist('jsonval')
    topics = request.form.getlist('topics')
    startDate = request.form.getlist('startDate')
    endDate = request.form.getlist('endDate')
    states = json.loads(states[0])
    print("start making session")
    try:
        session['states'] = states
    except:
        pass
    try:
        session['topics'] = topics
    except:
        pass
    try:
        session['startDate'] = startDate[0]
    except:
        pass
    try:
        session['endDate'] = endDate[0]
    except:
        pass
    print("END getting session")
    return redirect(url_for('us_news_bp.news_results', states=states, **request.args))
  else:
    q = "select DISTINCT supersection FROM articles;"
    conn = makeConn()
    dict_cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
    dict_cur.execute(q)
    topics = dict_cur.fetchall()
    return render_template('us_news.html',
                           title='Skeleton Site',
                           # states=states,
                           topics=topics,
                           subtitle='Homepage',
                           template='us_news-template')


def saveError(err):
    file = open("recent_error", "w")
    file.write(str(err))
    file.close()


@us_news_bp.route('/news_results')
def news_results():
    try:
        states = session['states']
        if len(states) == 0:
            states= '%'
        topics = session['topics']
        if len(topics) == 0:
            topics= '%'
        startDate = session['startDate']
        if len(startDate) == 0:
            startDate ='2000-01-01'
        endDate = session['endDate']
        if len(endDate) == 0:
            endDate = '2123-04-01'
        articles, pagination = getArticles(states, topics, startDate, endDate)
        return make_response(render_template(
                "news_results.html",
                articles=articles,
                pagination=pagination))
    except Exception as e:
        print(e)
        saveError(e)
        failure = schema.Error(
                        error = str(e),
                        step = 'news search',
                        date = datetime.now().isoformat())
        return render_template("errorpage.html")


def get_css_framework():
    return app.config.get("CSS_FRAMEWORK", "bootstrap4")


def get_link_size():
    return app.config.get("LINK_SIZE", "sm")


def get_alignment():
    return app.config.get("LINK_ALIGNMENT", "")

def show_single_page_or_not():
    return app.config.get("SHOW_SINGLE_PAGE", False)


def get_pagination(**kwargs):
    kwargs.setdefault("record_name", "records")
    return Pagination(
        css_framework=get_css_framework(),
        link_size=get_link_size(),
        alignment=get_alignment(),
        show_single_page=show_single_page_or_not(),
        **kwargs
    )


@click.command()
@click.option("--port", "-p", default=5000, help="listening port")
def run(port):
    app.run(debug=True, port=port)


if __name__ == "__main__":
    run()

Nginx配置

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;

include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 64;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;
    proxy_request_buffering off;


    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

#    map $http_upgrade $connection_upgrade {
#    default upgrade;
#    ''      close;
#}
    server {
        listen       80;
        listen       [::]:80;
        server_name  _;
        # root         /usr/share/nginx/html;
        return 301 https://$host$request_uri;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        error_page 404 /404.html;
        location = /404.html {
        }

        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }
}


## site.conf

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
    include /etc/nginx/default.d/*.conf;
    location / {
        include proxy_params;
#       proxy_http_version 1.1;
#        proxy_pass_request_headers on;
        proxy_request_buffering off;
        proxy_pass http://unix:/home/siteadmin/personal-website/siteapp.sock;
       # proxy_set_header Upgrade $http_upgrade;
#        proxy_set_header Connection $connection_upgrade;
#        proxy_ssl_session_reuse on;
#        proxy_intercept_errors off;
    }
}


## Proxy proxy_params

proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

内容的提问来源于stack exchange,提问作者Logos Masters

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 09:09:56