Flask 会话不保存数据

问题描述 投票:0回答:4

我有一个 Javascript 应用程序和一个 Flask 应用程序。当用户从 Js 向 Flask 发送数据时,我将其存储在

session
上,并且在特定路线上运行良好:

@app.route(...)
def user(...):
    session['name'] = name

    print(session['name']) # Works !

但是当我尝试从另一种方法/路线获取会话上的值时,会话为空:

@app.route(...)
def current():
    print(session.keys(), session.values) # Empty !

我已经安装了Flask Session并将配置设置为:

'SECRET_KEY': b'...',

'SESSION_TYPE': 'filesystem', # Memcache, null and redis

'SESSION_PERMANENT': False, # True

然后启动 Flask 应用程序,但它不起作用。在向会话添加一些新值后,我也尝试设置

session.modified = True
但仍然不起作用。

我在 Stack Over Flow、Reddit 等上阅读了很多帖子;但没有任何作用。请给点建议?

python session flask
4个回答
19
投票

TL;DR,在后端启用 CORS 和凭证支持,并在发出请求时在前端代码中使用凭证。

我最近遇到了类似的问题,我在单独的应用程序中开发前端和后端。我注意到,每次从前端客户端发出请求时,它都会为每个请求创建一个新会话,这会迅速使后端的会话存储膨胀,并使用户跟踪变得困难(如果不是不可能的话)。

我假设您的 Javascript 应用程序和 Flask 应用程序是单独运行的(即,javascript 不在 Flask 应用程序提供的模板上,因此 js 请求来自不同的来源)。

假设我们有一个启用 Flask-Session 的简单应用程序在端口 5000 上运行:

from flask import Flask, session
from flask_session import Session

app = Flask(__name__)

SECRET_KEY = "changeme"
SESSION_TYPE = 'filesystem'
app.config.from_object(__name__)
Session(app)

@app.route('/foo')
def foo():
    return session.sid


@app.route('/bar')
def bar():
    return session.sid

现在,如果我们在浏览器上导航到任一路由(例如,http://localhost:5000/foo)运行应用程序,我们将获得相同的会话 ID。如果您打开另一个选项卡,打开开发人员工具并在控制台中发出以下命令,您将收到 cors 错误:

// Using fetch, you can use jquery or axios    
fetch("http://localhost:5000/foo").then(response => {
    return response.text()
}).then(data => {
    console.log(data)
})

您可以通过安装 Flask-CORS 并将您的应用程序包装在 CORS 类中来轻松解决此问题:

from flask import Flask, session
from flask_session import Session
from flask_cors import CORS

app = Flask(__name__)

SECRET_KEY = "changeme"
SESSION_TYPE = 'filesystem'
app.config.from_object(__name__)
Session(app)
CORS(app)

@app.route('/foo')
def foo():
    return session.sid


@app.route('/bar')
def bar():
    return session.sid

现在,如果您运行上面的 javascript fetch 函数,它会在每次调用请求时打印出不同的会话 ID,即使对于相同的路由也是如此。这是因为 Flask 无法跟踪会话,除非您从同一来源发出请求,或者除非您为 Flask 提供某种方法来识别会话。您可以通过允许传递凭据来从 JS 执行此操作:

fetch("http://localhost:5000/foo",
    { credentials: 'include' }).then(response => {
        return response.text()
}).then(data => {
    console.log(data)
})

但是,您将收到另一个有关 Access-Control-Allow-Credentials 的 CORS 错误。您可以通过导入 cross_origin 装饰器、将路由包装在装饰器中并将supports_credentials=True 传递给装饰器来修复 Flask 应用程序中的此问题。烧瓶代码看起来像这样:

from flask import Flask, session
from flask_session import Session
from flask_cors import CORS, cross_origin

app = Flask(__name__)

SECRET_KEY = "changeme"
SESSION_TYPE = 'filesystem'
app.config.from_object(__name__)
Session(app)
CORS(app)

@app.route('/foo')
@cross_origin(supports_credentials=True)
def foo():
    return session.sid


@app.route('/bar')
@cross_origin(supports_credentials=True)
def bar():
    return session.sid

现在 Flask 可以跟踪请求者(在本例中为运行 Javascript 应用程序的浏览器)的会话。


9
投票

我在 html 中使用经典的 post 请求也遇到了同样的问题。该会话仍在之前的路由中存储值,在我发出请求后将自行清空。

我使用以下方法解决了这个问题:

app.config.update(SESSION_COOKIE_SAMESITE="None", SESSION_COOKIE_SECURE=True)

我分享这个以防其他人面临同样的问题。


0
投票

我的问题是会话cookie没有保存。 (不在 DevTools 的应用程序选项卡中)。在大多数情况下这可能是问题所在,因此请检查 DevTools。

修复方法如下:

所以基本上在 Flask 中,有一个 Http-Only cookie(无法在代码中访问的 cookie),它是在自动创建会话时创建的。

  • 首先,你需要启用CORS(就像大家在这里所说的那样)
# note that you are allowing all origins here, so put origins explicitly.

CORS(app, supports_credentials=True) # this sets Access-Control-Allow-Credentials header
  • 现在像这样配置应用程序:
app.secret_key = 'any_secret_key'
app.config['SESSION_COOKIE_SECURE'] = True # uses https or not
app.config['SESSION_COOKIE_SAMESITE'] = 'None' # cookie will be sent to another origin(client)

# this ensures that the session cookie is sent from your backend to the frontend securely.
# don't worry, this will also work on http when you are developing.
  • 在所有需要会话管理的获取请求中发送
    credentials: 'include'

-1
投票

对于任何将来阅读这篇文章并遇到 Daniyal 的 RuntimeError 问题的人来说,如果您说设置了 SECRET_KEY,则该错误最常见的是在加载配置之前运行 Session(app) 的结果。

© www.soinside.com 2019 - 2024. All rights reserved.