【问题标题】:Flask Session Not Persisting (Postman works, Javascript doesn't)Flask 会话不持久(邮递员有效,Javascript 无效)
【发布时间】:2018-09-17 15:19:31
【问题描述】:

我正在开发一个 Flask 服务器,用于通过网络在一些后端 Python 功能和 Javascript 客户端之间进行通信。我正在尝试利用 Flask 的 session 变量在用户与应用程序交互的过程中存储用户特定的数据。我已经删除了下面的大部分应用程序特定代码,但我遇到的核心问题仍然存在。

这是我的(简化的)Flask 应用程序的代码:

import json
import os
from flask import Flask, jsonify, request, session

app = Flask(__name__)
app.secret_key = 'my_secret_key'

@app.route('/', methods=['GET'])
def run():
  session['hello'] = 'world'
  return jsonify(session['hello'])

@app.route('/update', methods=['POST'])
def update():
  return jsonify(session['hello'])

if __name__ == '__main__':
  app.run(host='0.0.0.0')

使用 Postman,我可以向我的服务器发出 GET 请求并接收"world" 的预期输出。然后,我可以使用任意正文发出 POST 请求,并收到与 "world" 相同的预期输出(再次使用 Postman)。

使用 Chrome 时,我可以访问我的服务器 IP 并在页面上看到预期的输出 "world"。我还可以使用 Javascript(在 Chrome 的控制台中)手动发出 GET 请求,并收到与预期相同的响应。但是,当尝试使用 Javascript 向服务器发送 POST 请求时出现了我的问题;服务器在尝试发出此请求时显示KeyError: 'hello'。

这是我用来发出 POST 请求的 Javascript:

var url = 'http://my_server_ip/update';
fetch(url, {
  method: 'POST',
  body: JSON.stringify('arbitrary_string'),
  headers: new Headers({
    'Content-Type': 'application/json'
  })
})
.then(response => response.json())
.then((data) => {
  console.log(data);
})

这里出了什么问题?为什么我可以使用 Postman 发出 GET/POST 请求,但使用 Javascript 发出相同请求时却遇到错误?

【问题讨论】:

  • 您应该使用在请求“/”之后获得的 cookie 发布您的请求。
  • 令人惊讶的是,GET 在返回 world 的 JavaScript 请求中起作用。我尝试使用会话 cookie 标头,但 POST 请求仍然失败。

标签: javascript python json session flask


【解决方案1】:

经过几个小时的测试,我设法找出了问题所在。虽然我认为@amanb 的回答突出了问题,但我将回答我自己的问题,因为我发现最终是一个更简单的解决方案。

为了使 POST 请求返回预期值,我只需在 fetch 正文中添加一个 credentials: 'same-origin' 行。如下所示:

var url = 'http://my_server_ip/update';
fetch(url, {
  method: 'POST',
  body: JSON.stringify('arbitrary_string'),
  credentials: 'same-origin',   // this line has been added
  headers: {
    'Content-Type': 'application/json'
  }
})
.then(response => response.json())
.then((data) => {
  console.log(data);
})

根据Mozilla's Fetch usage guide,

默认情况下,fetch 不会从服务器发送或接收任何 cookie, 如果站点依赖于 维护用户会话。

看来我看过这个了。更改凭据以允许客户端和服务器之间的 cookie/会话通信解决了该问题。

【讨论】:

  • 啊,好吧,我想知道为什么这对我不起作用?看来我正在将凭据参数添加为标头。我现在已将其从我的答案中删除,以便人们更容易理解这两种情况的差异。
【解决方案2】:

fetch 文档的 caveats 部分说:

默认情况下,fetch 不会从服务器发送或接收任何 cookie,如果站点依赖于维护用户会话,则会导致未经身份验证的请求。

推荐使用AJAX与Flask视图交换信息。

同时,在您的 Flask 应用程序代码中,session 对象是一个字典。现在,如果您使用其键 session['hello'] 访问字典,并且如果该键不存在,则会引发 Keyerror。要解决此错误,您可以对字典使用 get() 方法。

发生的情况是:fetch 请求在 Flask 会话中找不到 hello 键(或从 Flask 视图获取会话值)。

user = session.get('hello')
return jsonify(session_info=user)

但这仍然会为会话{ session_info: null } 提供null 值。为什么呢?

当您向 Flask 服务器发送 GET/POST 请求时,会在 Flask 中初始化和查询会话。但是,当您发送 Javascript fetch POST 请求时,您必须首先从 Flask 获取会话值,然后将其作为 POST 请求发送到 returns 会话信息的 Flask 视图。

在您的代码中,当从fetch 触发 POST 请求时,当我将有效负载数据发送到 Flask 时,它会被正确接收,您可以在 Flask 视图中使用request.get_json() 进行检查:

@app.route('/update', methods=['POST'])
def update():
  user = session.get('hello')
  payload = request.get_json()
  return jsonify(session_info=user, payload=payload)

这将返回{ payload: 'arbitrary_string', session_info: null }。这也说明fetch没有收到会话信息是因为我们没有先调用GET从Flask获取会话信息。

记住:Flask 会话位于 Flask 服务器上。要通过 Javascript 发送/接收信息,您必须进行单独调用,除非有存储会话 cookie 的规定。

const fetch = require('node-fetch');

var url_get = 'http://my_server_ip';
var url_post = 'http://my_server_ip/update';
fetch(url_get, {
  method:'GET'
}).then((response)=>response.json()).then((data) =>fetch(url_post, {
  method: 'POST',
  body: JSON.stringify(data),
  dataType:'json',
  headers: {
    'Content-Type': 'application/json'
  }
})
.then(response => response.json())
.then((postdata) => {
  console.log(postdata);
}));

Flask 视图会略有变化:

@app.route('/', methods=['GET'])
def set_session():
    session['hello'] = 'world'
    return jsonify(session['hello'])

@app.route('/update', methods=['POST'])
def update():
    payload = request.get_json()
    return jsonify(session_info=payload)

当您现在触发 Javacript 请求时,输出将是:{ session_info: 'world' }

【讨论】:

    猜你喜欢
    • 2017-01-30
    • 2021-01-14
    • 2018-03-29
    • 2018-08-05
    • 2021-04-09
    • 2012-11-20
    • 2012-03-17
    • 2013-03-02
    • 2020-07-10
    相关资源
    最近更新 更多