Сеанс Flask не сохраняется (Postman работает, Javascript-нет)



Я разрабатываю сервер 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')


Используя почтальона, я могу сделать запрос GET к мой сервер и получить ожидаемый результат "world". Затем я могу сделать запрос POST с произвольным телом и получить тот же ожидаемый результат "world" (снова используя Postman).



При использовании Chrome я могу посетить IP-адрес своего сервера и увидеть ожидаемый результат "world" на странице. Я также могу вручную сделать запрос GET с помощью Javascript (в консоли Chrome) и получить тот же ответ, что и ожидалось. Однако моя проблема возникает при попытке отправить POST-запрос на сервер с помощью Javascript; сервер показывает KeyError: 'hello' при попытке сделать этот запрос.



Вот Javascript, который я использую для запроса POST:



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);
})


Что здесь не так? Почему я могу сделать запросы GET/POST с Postman просто отлично, но столкнуться с ошибками, делая те же запросы с Javascript?

616   2  

2 ответов:

После нескольких часов тестирования мне удалось выяснить эту проблему. Хотя я думаю, что ответ @user8212173 подчеркивает проблему, я собираюсь ответить на свой собственный вопрос, потому что то, что я нашел, в конечном счете является более простым решением.

Для того, чтобы запрос POST вернул ожидаемое значение, мне просто нужно было добавить строку credentials: 'same-origin' в тело fetch. Это выглядит следующим образом:

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);
})

Согласно руководству по использованию Fetch от Mozilla ,

По умолчанию, fetch не будет отправить или получить файлы cookie с сервера, что приводит к несанкционированным запросам, если сайт полагается на ведение сеанса пользователя.

Итак, кажется, я просмотрел это. Изменение учетных данных, чтобы разрешить обмен файлами cookie / сеансами между клиентом и сервером, решило проблему.

Разделпредостережений документации fetch гласит:

По умолчанию fetch не отправляет и не получает никаких файлов cookie с сервера, что приводит к несанкционированным запросам, если сайт полагается на поддержание сеанса пользователя.

Рекомендуется использоватьAJAX для обмена информацией с видами Колб.

Между тем, в вашем коде для приложения Flask объект session является словарем. Теперь, если вы получаете доступ к словарю с его ключом session['hello'] и если этот ключ не существует, то возникает Keyerror. Чтобы обойти эту ошибку, вы можете использовать метод get() для словарей.

Происходит следующее: запрос fetch не находит ключ hello (или не получает значение сеанса из представления колбы) в сеансе колбы.

user = session.get('hello')
return jsonify(session_info=user)
Но это все равно даст вам значение null для сеанса { session_info: null }. Почему это так?

Когда вы отправляете запросы GET / POST на сервер Flask, сеанс инициализируется и запрашивается изнутри Колба. Однако при отправке запроса POST Javascript fetch необходимо сначала получить значение сеанса из Flask, а затем отправить его в виде запроса POST в представление Flask, которое returnсодержит информацию о сеансе.

В вашем коде, когда запрос POST запускается из fetch, Когда я отправляю данные полезной нагрузки в Flask, они принимаются правильно, и вы проверяете это с помощью request.get_json() в представлении Flask:

@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 first, чтобы получить информацию о сеансе от 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' }

Comments

    Ничего не найдено.