Flask/Python/Gunicorn/Nginx WebApp 在提交 Flask WTForm 时从目标网页删除 https

Flask/Python/Gunicorn/Nginx WebApp dropping https from target web page when submitting Flask WTForm

这是我第一次在 Whosebug 上提交,希望我能提供足够的细节。

我一直在构建一个 Python/Flask 网络应用程序,大致基于 博客中使用的框架 米格尔·格林伯格

它在我的 PyCharm IDE 中运行良好,问题是当我在 Flask 服务器上使用 Gunicorn 和 NginX 将它部署到 Oracle VirtualBox 上的 ubuntu 服务器时。

Web 应用程序由 10 个 pages/templates 组成,当在 Virtulbox 上部署和 运行 时,我可以在我的主机浏览器上很好地浏览应用程序,直到我提交一个 FlaskForm,然后应该 return 包含所需数据的结果页面。

它应该 return https://127.0.0.1:3000/results 但是 return 只是 http: http://127.0.0.1:3000/results

(https 已降为 http)

和结果

400 错误请求

纯 HTTP 请求已发送到 HTTPS 端口

nginx/1.18.0 (Ubuntu)

这个错误是不言自明的,我知道它可能在 nginx 配置中的某处我不知道的地方(我试图解决这个问题一周左右)

 /etc/nginx/sites-enabled/highceesdev:

server {
# listen on port 80 (http)
listen 80;
server_name _;
location / {
    # redirect any requests to the same URL but on https
    return 301 https://$host$request_uri;
}

}

server {
# listen on port 443 (https)
listen 443 ssl;
server_name _;

# location of the self-signed SSL certificate
ssl_certificate /home/ubuntu2/HighCees/HighCeesDev/certs/cert.pem;
ssl_certificate_key /home/ubuntu2/HighCees/HighCeesDev/certs/key.pem;

# write access and error logs to /var/log
access_log /var/log/highceesdev_access.log;
error_log /var/log/highceesdev_error.log;

location / {
    # forward application requests to the gunicorn server
    proxy_pass http://localhost:8000;
    proxy_redirect off;
    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;
}

location /static {
    # handle static files directly, without forwarding to the application
    alias /home/ubuntu2/HighCees/HighCeesDev/app/static;
    expires 30d;
}

}

如果相关,进一步代码如下。

正在提交的 FlaskForm 的定义是 HighCeesDev/app/forms.py:

....
class CreateSong2(FlaskForm):
startdate = DateField('Start Date', default=(datetime.today()-timedelta(90)),format='%Y-%m-%d',validators=(validators.data_required(),))
enddate = DateField('End Date', default=datetime.today(),format='%Y-%m-%d', validators=(validators.data_required(),))
city = RadioField(choices=[('Wellington', 'Wellington'), ('Auckland', 'Auckland'),('Christchurch', 'Christchurch'), ('Dunedin', 'Dunedin')])
submit = SubmitField('Submit')

...

CreateSong2(FlaskForm) 的路由定义和结果 HighCeesDev/app/routes.py:

@app.route('/create_song2',methods=['GET','POST'])
def create_song2():
latedate = Song.query.order_by(Song.date.desc()).first()
startdate = Song.query.order_by(Song.date.asc()).first()
convertedlatedate1=latedate.date
convertedlatedate2 = convertedlatedate1.strftime("%d/%m/%Y")
convertedstartdate1=startdate.date
convertedstartdate2 = convertedstartdate1.strftime("%d/%m/%Y")
form = CreateSong2()
if form.validate_on_submit():
    session['startdate'] = form.startdate.data
    session['enddate'] = form.enddate.data
    session['shcity'] = form.city.data
    shcity = form.city.data
    purge_files()
    return redirect(url_for('results'))
return render_template('create_song2.html',form=form, latedate=latedate, startdate=startdate,convertedlatedate2=convertedlatedate2, convertedstartdate2=convertedstartdate2)

@app.route('/results',methods=['GET','POST'])
def results():
startdate = session['startdate']
endate= session['enddate']
shcity = session['shcity']
form=Results()
startedate = extract_date_sequel(startdate)
finishedate = extract_date_sequel(endate)
song = Song.query.filter(Song.date <= finishedate,Song.date >= startedate,Song.city==shcity).order_by(Song.date.asc())
song2 = Song.query.with_entities(Song.high_temp).filter(Song.date <= finishedate,Song.date >= startedate,Song.city==shcity).order_by(Song.date.asc())
if not check_song_query(song2):
    print("check_song_query says its False :-(!!")
    flash("No data in that query :-(")
    return redirect(url_for('create_song2'))
else:
    print("check_song_query says its True!!")
print("song is: ", type(song))
print("song2 is: ",type(song2))
a = []
for i in song2:
    stringy = ''
    stringy = stringy.join(i._data)
    a.append(stringy)
print(type(a))
print(a)
songfile = SongFileEvent.query.all()
dtf = date_time_file_wav()
record = SongFileEvent(song_file_name=dtf)
db.session.add(record)
db.session.commit()
testy2(a)
daft = SongFileEvent.query.order_by(SongFileEvent.id.desc()).first()
songfile = SongFileEvent.query.all()
now = time.time()
purge_files_2(now)
print("purge files was called")
#convert_numbers_to_notes(a)
return render_template('results.html',title='Home', song=song, songfile=songfile, daft=daft)

如果有帮助,希望提供更多详细信息。

非常感谢

帕特

在您的部署中,您的视图是 运行 在 http 请求的上下文中 - http://localhost:8000url_for 将 return URL 与 'http' 协议.

您需要使用特定的 configuration settings 设置 Flask 实例。我发现以下两个设置可以解决此类问题:

PREFERRED_URL_SCHEME

SERVER_NAME

一个简单的例子。

# app/config.py

class Config(object):
    # common configurations
    SECRET_KEY = 'XXXXXXX'
    MAX_CONTENT_LENGTH = 32 * 1024 * 1024

    ### more settings


class DevelopmentConfig(Config):
    # specific configurations
    SERVER_NAME = "example.local:5072"
    PREFERRED_URL_SCHEME = 'http'

    ### more settings


class ProductionConfig(Config):
    # specific configurations
    SERVER_NAME = "example.com"
    PREFERRED_URL_SCHEME = 'https'

    ### more settings


# app/__init__.py

def create_app():
    app = App(__name__)
    
    # APP_SETTINGS is an environment variable either set to:
    # export APP_SETTINGS=app.config.DevelopmentConfig
    # or
    # export APP_SETTINGS=app.config.ProductionConfig

    app.config.from_object(os.environ['APP_SETTINGS'])

    ### more setup

    return app

Nginx 代理设置

location / {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_redirect off;
    proxy_pass http://localhost:8000;
    proxy_set_header X-Sendfile-Type X-Accel-Redirect;
}