Flask会话没有持久化(Postman有效,Javascript不行)

2024-04-27 03:08:45 发布

您现在位置:Python中文网/ 问答频道 /正文

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

以下是我的(简化)烧瓶应用程序的代码:

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:

^{pr2}$

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


Tags: 用户import服务器app应用程序利用flaskhello
2条回答

fetch文档的caveats部分说明:

By default, fetch won't send or receive any cookies from the server, resulting in unauthenticated requests if the site relies on maintaining a user session.

建议使用AJAX与烧瓶视图交换信息。在

同时,在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 fetchPOST请求时,必须首先从Flask获取会话值,然后将其作为POST请求发送到Flask视图,该视图return是会话信息。在

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

^{pr2}$

这将返回{ payload: 'arbitrary_string', session_info: null }。这还表明,fetch没有收到会话信息,因为我们没有调用getfirst从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);
}));

烧瓶视图将略有变化:

@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' }

经过几个小时的测试,我设法解决了这个问题。虽然我认为@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

By default, fetch won't send or receive any cookies from the server, resulting in unauthenticated requests if the site relies on maintaining a user session.

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

相关问题 更多 >