问题描述
当我尝试使用 gunicorn -w 3 wsgi:app
运行 Flask 并通过 IP 地址访问页面时,我收到以下错误:RuntimeError: A secret key is required to use CSRF.
在终端中。
我不确定是什么导致了这个问题,因为:我在 .env
中设置了一个密钥并且我确认它正在被 Flask 加载,因为当我使用 flask run --host=0.0.0.0
运行应用程序时,然后代码print(app.config['SECRET_KEY'])
将密钥打印到终端。
我想这与 Gunicorn 需要不同的代码来加载密钥有关。
我的 Flask 应用的结构如下:
-denise
--configmodule.py
--__init__.py
--site.db
--models.py
--main
--static
--template
-migrations
-venv
-wsgi.py
-.env
from flask import Flask
from flask_sqlalchemy import sqlAlchemy
from denise.configmodule import Config
from flask_bcrypt import Bcrypt
from flask_login import LoginManager
from flask_mail import Mail
from flask_migrate import Migrate
from flask_wtf.csrf import CSRFProtect
db = sqlAlchemy()
bcrypt = Bcrypt()
login_manager = LoginManager()
mail = Mail()
csrf = CSRFProtect()
def create_app():
app = Flask(__name__)
app.config.from_object(Config)
csrf.init_app(app)
migrate = Migrate(app,db)
db.init_app(app)
bcrypt.init_app(app)
login_manager.init_app(app)
mail.init_app(app)
print('SECRET_KEY')
print(app.config['SECRET_KEY'])
print('SECRET_KEY')
#with app.app_context()
from .main.routes import main
app.register_blueprint(main)
return app
from os import environ,path
from dotenv import load_dotenv
basedir = path.abspath(path.dirname(__file__))
load_dotenv(path.join(basedir,'.env'))
class Config(object):
DEBUG=True
SECRET_KEY=environ.get('SECRET_KEY')
sqlALCHEMY_DATABASE_URI='sqlite:///site.db'
ENV='development'
MAIL_SERVER = 'smtp.googlemail.com'
MAIL_PORT = 587
MAIL_USE_TLS = True
MAIL_USERNAME = environ.get('EMAIL_USER')
MAIL_PASSWORD = environ.get('EMAIL_PASS')
MAIL_DEFAULT_SENDER = environ.get('EMAIL_DEFAULT_SENDER')
MAIL_MAX_EMAILS = 5
RECAPTCHA_PUBLIC_KEY = environ.get('RECAPTCHA_PUBLIC')
RECAPTCHA_PRIVATE_KEY = environ.get('RECAPTCHA_PRIVATE')
from denise import create_app
from dotenv import load_dotenv
load_dotenv('.env')
app = create_app()
if __name__ == "__main__":
app.run()
.env 文件:
SECRET_KEY='hiiii17011b97b7ed4aeb9ae7f75a0b66a006c8efd4ab0759e5d2'
EMAIL_USER='email@email.email'
EMAIL_DEFAULT_SENDER='email@email.email'
EMAIL_PASS='password'
RECAPTCHA_PUBLIC='randomstringofletter'
RECAPTCHA_PRIVATE='lalalalalal'
我尝试了 Corey Schafer 和 Pretty Printed 的一些关于将 Flask 应用程序部署到生产环境的教程。我想我在某处错过了一些东西。
解决方法
(用手机写的)
看看你的 wsgi 文件:
- 首先导入 create_app,它会转到您的
__init__
文件 -
__init__
文件导入 Config,它不是延迟初始化,而是在导入时(我会更改此设置,但这不是问题) - 在配置文件中取
__file__
的目录名,即denise
,然后用.env
加入它,而denise目录中没有env文件
关于运行flask run调试,我不使用flask,但它可能只是不使用wsgi文件。
,很好的旧垃圾邮件打印语句来救援。
注意,我使用 gunicorn -w 1 -t 1 wsgi:app
来确保单个工作线程和线程,否则控制台会收到来自多个来源的 print
语句的垃圾邮件。
导入和加载订单可能是罪魁祸首。 load_dotenv(path.join(basedir,'.env'))
中的语句 configmodule.py
也存在问题。它在目录 .env
中查找 denise
文件并无提示地失败。
我制作了一个可重现的例子,见下文。
解决方法是:
- 在从
load_dotenv('.env')
导入任何内容之前先在wsgi.py
中执行denise
- 将您在
configmodule.py
中的加载方式更改为load_dotenv(path.join(basedir,'../.env'))
,但由于您使用了应用程序工厂模式结构,我不确定这是否可取。这可能会导致未来出现不良行为。
configmodule.py
>from os import environ,path
from dotenv import load_dotenv,dotenv_values
from pprint import pprint
print('--------------------------------------------------------------------------------------------------------------------------------')
print('configmodule')
print('--------------------------------------------------------------------------------------------------------------------------------')
basedir = path.abspath(path.dirname(__file__))
load_dotenv(path.join(basedir,'.env'))
try:
with open(path.join(basedir,'.env')) as infile:
for line in infile:
print(line)
except:
print('=========================== FILENOTFOUND')
class Config(object):
print('--------------------------------------------------------------------------------------------------------------------------------')
print('configmodule:Config')
print('--------------------------------------------------------------------------------------------------------------------------------')
pprint(dotenv_values(path.join(basedir,'.env')))
print('--------------------------------------------------------------------------------------------------------------------------------')
pprint(environ)
DEBUG=True
SECRET_KEY=environ.get('SECRET_KEY')
SQLALCHEMY_DATABASE_URI='sqlite:///site.db'
ENV='development'
MAIL_SERVER = 'smtp.googlemail.com'
MAIL_PORT = 587
MAIL_USE_TLS = True
MAIL_USERNAME = environ.get('EMAIL_USER')
MAIL_PASSWORD = environ.get('EMAIL_PASS')
MAIL_DEFAULT_SENDER = environ.get('EMAIL_DEFAULT_SENDER')
MAIL_MAX_EMAILS = 5
RECAPTCHA_PUBLIC_KEY = environ.get('RECAPTCHA_PUBLIC')
RECAPTCHA_PRIVATE_KEY = environ.get('RECAPTCHA_PRIVATE')
wsgi.py
>from os import environ
from denise import create_app
from dotenv import load_dotenv,dotenv_values
print('--------------------------------------------------------------------------------------------------------------------------------')
print('WSGI')
print('--------------------------------------------------------------------------------------------------------------------------------')
load_dotenv('.env')
print(dotenv_values('.env'))
print('--------------------------------------------------------------------------------------------------------------------------------')
with open('.env') as infile:
print(infile.readlines())
print('--------------------------------------------------------------------------------------------------------------------------------')
print(environ)
print('--------------------------------------------------------------------------------------------------------------------------------')
app = create_app()
if __name__ == "__main__":
app.run()
我建议修改 wsgi.py
以防止未来出现问题,如上所述,尽管这可能违反 PEP8 标准。
固定的 wsgi.py
>from dotenv import load_dotenv
load_dotenv('.env')
from denise import create_app
app = create_app()
if __name__ == "__main__":
app.run()