Flask:为每个响应设置Cookie

8

我在我的应用程序中使用Flask会话。在我的处理程序之一中,我设置了会话值,在其他处理程序中没有设置会话。但是,我发现在每个响应中都存在一个HTTP头:Set-Cookie。为什么会这样?

app = Flask(__name__)
app.secret_key = r"A0Zr98j/3yX R~XHH!jmN'LWX/,?RT"

@app.route('/auth/login', methods=['POST'])
@crossdomain(origin='*')
def authlogin():
    user = User(username=username, registered_at=sqlnow())
    user.accounts = [Account(provider='weibo', access_token=access_token, uid=uid)]
    account = user.accounts[0]

    session['user_id'] = account.user_id
    return jsonify({
        'status': 'success',
        'data': {
            'user_id': account.user_id,
            'uid': account.uid
        }
    })

@app.route('/api/movies/<movie_type>')
def moviescoming(movie_type):
    if movie_type == 'coming':
        return getmovies(MOVIE_TYPE_PLAYING, offset, limit)
    else:
        return getmovies(MOVIE_TYPE_COMING, offset, limit)

app.run(host='0.0.0.0', debug=True)

这里展示代码: https://github.com/aisensiy/dianying/blob/master/index.py


如果您提供了一个最小的Flask应用程序示例,其中包含一个视图设置会话值,另一个视图不设置,而不是粘贴包含所有复杂视图逻辑的大量代码,那将非常好。 - Mark Hildreth
@MarkHildreth 谢谢您的建议。我已经清理了我的代码。希望这对您有所帮助。 - aisensiy
1个回答

22

简短回答:

这是出于设计原因,但 Flask 的最新更改允许您通过使用 SESSION_REFRESH_EACH_REQUEST 选项来更改此行为。截至本答案发布时,该选项尚未包含在 Flask 的稳定版本中。

详细回答:

让我们回到开始讨论 cookie 应该如何工作的问题:

标准的 Cookie

RFC 6265 规定,除非提供了某种机制告诉浏览器 cookie 应该何时过期,否则当代理(浏览器)声明会话关闭(通常在关闭浏览器时)时,cookie 应该过期

除非 cookie 的属性另有规定,否则 cookie 在当前会话结束时过期(由用户代理定义)。

[...]

如果 cookie 没有 Max-Age 或 Expires 属性,则用户代理将保留 cookie 直到“当前会话结束”(由用户代理定义)。

如果服务器希望Cookie在代理重启后仍然存在,则需要设置过期时间。请注意,由于Internet Explorer存在max-age支持不佳的历史,因此通常更喜欢使用Expires属性。

创建永久Cookie

因此,无法说Cookie应该是“永久”的。当人们谈论“永久”Cookie时,他们真正谈论的是一个可以在浏览器重启后保留的Cookie。我知道有两种策略可以创建这个“永久”Cookie:

  • 将Cookie的过期时间设置为足够长,被认为是永久的(例如年份9999)。
  • 将Cookie的过期时间设置为相对较近的未来时间(例如31天),但每次使用Cookie时都会再次更新过期时间。例如,在1月1日我们将Cookie设置为在2月1日过期,但当用户在1月2日使用Cookie时,我们通过使用Set-Cookie更新Cookie,使其在2月2日过期。
第一种方法要求 Set-Cookie 头只在客户端首次设置(除非 cookie 内容需要更改)。
第二种方法需要在每次更新时发送 Set-Cookie 标头,以便在用户继续使用服务时不断“推迟”到期时间。请注意,它也不是真正的“永久性”,因为超过 31 天不使用您网站的用户将使其 cookie 过期。
RFC 6265 对 定义过期日期 有一些说明:

虽然服务器可以将 cookie 的过期日期设置为遥远的未来,但大多数用户代理实际上并不会保留 cookie 多十年。服务器不应该选择毫无意义的长期过期时间,而应根据 cookie 的目的合理选择 cookie 的过期时间,从而促进用户隐私。例如,一个典型的会话标识符可能在两周内过期。

因此,尽管它没有明确说明是否要不断更新到期日期,但似乎它确实表明使用遥远的未来日期不应被视为一种良好的做法。

Flask对“Permanent Cookies”的实现

Flask采用第二种方法(使用Set-Cookie不断更新cookie的过期时间)进行设计。默认情况下,cookie的过期时间是31天(可由PERMANENT_SESSION_LIFETIME进行配置)。每个请求都会使Flask使用另一个Set-Cookie将cookie的过期时间再次延长31天(或您设置的permanent session lifetime值)。因此,即使会话未更改,您在每个请求中看到的Set-Cookie也是可以预期的。

最近,关于仅在cookie更改时使用Set-Cookie的讨论已经出现在拉取请求中。这导致了一个新功能,允许用户更改其工作方式。Flask将继续按照原来的方式工作,但用户可以将新的SESSION_REFRESH_EACH_REQUEST选项设置为False,这将导致只有在cookie更改时才发送Set-Cookie标头。
新项目的文档如下:

此标志控制永久会话的刷新方式[sic]。如果设置为True(默认值),则每个请求都会刷新cookie,从而自动增加寿命。如果设置为False,则仅在会话被修改时才发送set-cookie标头。非永久会话不受此影响。

这个新选项和现有的PERMANENT_SESSION_LIFETIME选项一起,允许Flask开发人员更好地调整他们的“永久”cookie的到期时间。截至本答案发布日期(2013年12月24日),SESSION_REFRESH_EACH_REQUEST选项尚未成为任何Flask版本的一部分,因此希望使用它的用户将需要等待未来的Flask版本。

感谢您的回答。为每个http设置cookie非常奇怪。这让前端开发人员认为这是一个错误。我们都使用第一种方法来确保永久会话。 - aisensiy
@NathanWailes 谢谢,已修复。 - Mark Hildreth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接