LINUX.ORG.RU

Как во flask в POST запросе сохранить данные для обработки в GET

 , , ,


0

3

Привет, ЛОР!

Написал функцию на js, от которой хочу следующее. Функция из другой функции получает строку и отправляет ее на бэкенд (в моем случае маршрут flask /cart/test_js) и, в случае успеха, редиректит на этот адрес.

Полный код js:

// Function to send docsIds to flask backend (route /cart/test_js).
onst sendDocsIdsToFlask = () => {
    const docsIds = getDocsIds();

    // Create an AJAX request object
    const xhr = new XMLHttpRequest();

    // Set up the request headers and data
    xhr.open("POST", "/cart/test_js", true);
    xhr.setRequestHeader("Content-Type", "application/json");

    // Convert the docsIds variable to a JSON string
    const jsonData = JSON.stringify({ docsIds: docsIds });

    // Send the AJAX request
    xhr.send(jsonData);

    // Handle the response from the server
    xhr.onload = function () {
        if (xhr.status === 200) {
            // console.log("Success!");
            window.location.href = "http://127.0.0.1:5000/cart/test_js";
        } else {
            console.error("Error:", xhr.statusText);
        }
    };

    // Handle any errors that occur during the request
    xhr.onerror = function () {
        console.error("Error occurred:", xhr.statusText);
    };
}

Код маршрута во flask:

@bp.route("/test_js", methods=["GET", "POST"])
@login_required
def test_js():
    print(f"{request.get_json()=}")
    return redirect(url_for('main.index'))

Это не работает. В консоли вижу ошибку

[Error] Failed to load resource: the server responded with a status of 415 (UNSUPPORTED MEDIA TYPE) (test_js, line 0)

Погуглив ошибку, нашел только, что это из-за того, что не указан тип отправляемых данных, хотя он у меня указан (application/json).

Вопросы: 1) как это пофиксить? 2) как при редиректе использовать не захардкоденные адреса, а динамичные из flask типа url_for(...)?



Последнее исправление: Xld (всего исправлений: 2)
  1. как при редиректе использовать не захардкоденные адреса, а динамичные из flask типа

Ты редирект делаешь на клиенте, вот и делай.

    return flask.jsonify({
         "redirect_url": "main.html"
    }), 200

а на клиенте

    const response = JSON.parse(xhr.response);
    window.location.href = "/" + response.redirect_url;
Skullnet ★★★★★
()
Последнее исправление: Skullnet (всего исправлений: 1)
Ответ на: комментарий от Skullnet

Редирект на сервере у меня, получается.

Я думаю, что можно ведь просто функции sendDocsIdsToFlask(route) передать маршрут в html в атрибутах кнопки и все. Вроде, должно сработать.

По поводу первого вопроса не подскажешь? Я может неправильно понимаю способ передачи данных через Ajax?

Xld
() автор топика

jQuery

$.ajax({
  type: 'POST',
  url: '/cart/test_js',
  data: { docsIds }, // так можно если ключ совпадает с именем переменной
  success: () => window.location.href = "http://127.0.0.1:5000/cart/test_js",
  dataType: 'json'
});
MOPKOBKA ★★★★★
()

Название темы неправильное, у тебя вопрос не про js (с ним ты всё сделал правильно) а про тот самый бекэнд, у которого не пойми какие требования которых ты не знаешь. И раздел форума неправильный, надо в web-development.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от firkax

Спасибо за критику. А конкретнее можешь объяснить, что не так с «требованиями бэкэнда»? Вроде, обычный маршрут, обычный POST запрос.

Я делаю для себя веб приложение, это не промышленная разработка, очевидно. Понимаю, что вопрос может показаться нубским, но для этого и нужны вопросы, разве нет? Если что-то еще нужно указать, скажи, напишу, если знаю.

Xld
() автор топика
Ответ на: комментарий от Xld

Ну, ошибку 415 тебе бекэнд возвращает, вот и ищи что ему не нравится. Ещё можно в браузере в отладочной консоли проверить какие именно заголовки у запроса на всякий случай, а ещё сравнить их с теми которые работают.

firkax ★★★★★
()
Ответ на: комментарий от MOPKOBKA

Я с jquery не знаком от слова совсем. С js то всего неделю вожусь. Почитал про jquery, получилось так

function sendDocsIdsToFlask() {
    const docsIds = getDocsIds();
    $.ajax({
        url: '/cart/test_js',
        type: 'POST',
        dataType: 'json',
        data: JSON.stringify(docsIds),
        success: function (response) {
            window.location.href = "http://127.0.0.1:5000/cart/test_js";
        },
        error: function (error) {
            console.log(error);
        }
    });
}

Ошибка

Did not attempt to load JSON data because the request Content-Type was not 'application/json'.

Подозреваю, что дело в docsIds. Это массив. JSON.stringify по идее должен его преобразовать в json строку. Почему тогда в ошибке говориться про неподдерживаемый формат, не понимаю…

Xld
() автор топика
Ответ на: комментарий от firkax

У меня flask в режиме дебага работает. Если ошибка возникает на его стороне, там спец. форма дебаг лога на странице (Werkzeug don’t panic). Тут это просто страница, без дебага, и в логах flask я не вижу этого POST запроса. Поэтому, считаю, что до него он и не дошел, что ли. Я не прав?

В консоле браузера, кстати, тоже кроме ошибки, которую я передал, ничего нет.

Xld
() автор топика
Ответ на: комментарий от Xld

А точно у тебя урл правильно указан? Может у тебя фласк на другом порту запущен, не как фронт и нужно написать что-то вроде url: 'http://127.0.0.1:8080/cart/test_js'?

masa
()
Ответ на: комментарий от Xld

Проверь в логах сети браузера что точно шлётся и что приходит в ответ.

firkax ★★★★★
()

Я бы сделал так:

const sendDocsIdsToFlask = async () => {
    const docsIds = getDocsIds();

    try {
        const response = await fetch("/cart/test_js", {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
            },
            body: JSON.stringify({ docsIds: docsIds }),
        });

        if (response.ok) {
            window.location.href = "http://127.0.0.1:5000/cart/test_js";
        } else {
            console.error("Error:", response.statusText);
        }
    } catch (err) {
        console.error("Error occurred:", err.message);
    }
};

На чистом JS достаточно «кросбраузерно» и без всяких библиотек…

romanlinux ★★★
()
Последнее исправление: romanlinux (всего исправлений: 1)

Кстати, если у тебя flask возвращает 415ую ошибку после редиректа (GET запроса грубо говоря), то стоит проверить, может ли он у тебя «поддерживать» еще какие нибудь запросы кроме application/json?

потому что POST запрос идет как JSON запрос с заголовком "Content-Type", "application/json" а GET запрос, который как бы «редирект» может «идти» с другим заголовком и его flash похоже не хочет обрабатывать…

romanlinux ★★★
()
Ответ на: комментарий от Xld

Ну тогда ты должен видеть в логах фласка этот запрос.

По этой ошибке:

[Error] Failed to load resource: the server responded with a status of 415 (UNSUPPORTED MEDIA TYPE) (test_js, line 0)

Тут тебе надо и с фронта при запросе посылать content-type и на беке его возвращать

masa
()
Ответ на: комментарий от romanlinux

Спасибо, буду изучать. Тут еще и асинхронность, до которой я пока не дошел. Жаль, но на выполнение этой функции так же ошибка.

Xld
() автор топика
Ответ на: комментарий от Xld

Тут еще и асинхронность

У Flask-а нету asynchronous API. Если тебе нужна асинхронность то сразу переписывай на quart, а то потом сложно будет.

Skullnet ★★★★★
()
Ответ на: комментарий от romanlinux

Вот я проверяю на стороне flask, что мне шлет фронт:

@bp.route("/test_js", methods=["GET", "POST"])
@login_required
def test_js():
    print(f"{request.is_json=}")
    print(f"{request.form=}")
    return redirect(url_for('main.index'))

В логе

request.is_json=False
request.form=ImmutableMultiDict([])

Получается, что данных в запросе вообще не приходит, раз форма пустая?

Xld
() автор топика
Ответ на: комментарий от masa

Выше дал принты о типы получаемого объекта. Бэк вообще не получает ничего…

Xld
() автор топика
Ответ на: комментарий от Xld

Нужно добавить еще такое

contentType: 'application/json; charset=utf-8',
забыл совсем.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от Xld

Так да. У тебя походу «проблема» в бэкенде. что пишет браузер если просто в соседней вкладке открыть http://127.0.0.1:5000/cart/test_js?

или сделать команду curl http://127.0.0.1:5000/cart/test_js?

romanlinux ★★★
()
Ответ на: комментарий от Xld

А это такой ответ на POST или на GET?

Может лучше сделать «две разные ручки» под POST и GET?

Потому что походу на POST у тебя будет JSON туда сюда слаться, а на GET будет html отдаваться?

romanlinux ★★★
()
Последнее исправление: romanlinux (всего исправлений: 1)
Ответ на: комментарий от romanlinux

Я немного переделал код

@bp.route("/test_js", methods=["GET", "POST"])
@login_required
def test_js():
    return request.form

Чтобы просто возвращал через GET, что отправлено через POST.

function sendDocsIdsToFlask() {
    const docsIds = getDocsIds();
    // const docsIdsJSON = JSON.stringify({docsIds});
    $.ajax({
        url: 'http://127.0.0.1:5000/cart/test_js',
        type: 'POST',
        contentType: 'application/json',
        dataType: 'json',
        data: {'docsIds': docsIds},
    });
    window.location.href = "http://127.0.0.1:5000/cart/test_js";
}

На выходе получаю пустоту:

{}

Данные просто не доходят, что-ли… По поводу разделения, я попробовал оставить для маршрута только POST, а вместо возврата чего-либо принтом выводить в лог данные формы - в логе те же самые {}.

Xld
() автор топика
Ответ на: комментарий от Xld

Есть разные способы кодирования формы, application/x-www-form-urlencoded, multipart/form-data, application/json. Я фласк только немного видел, но по идее тут с этим несоответствие. Нагугли какой-то хелловорд на фласке по отправке жсона и проблема решена.

goingUp ★★★★★
()
Последнее исправление: goingUp (всего исправлений: 1)
Ответ на: комментарий от goingUp

Все, что я нагуглил, я попробовал. Везде +- одно и тоже. Отправляешь через jQuery/AJAX, на стороне flask получаешь в виде request, используешь. Вроде, все просто, но не работает.

Xld
() автор топика
Ответ на: комментарий от Xld

В смысле, у вас не работают готовые примеры?

goingUp ★★★★★
()
Ответ на: комментарий от Xld

Я не пишу на питухоне, но похоже проблема в том, что у тебя JSON запрос, а ты пытаешь получить данные как будто из «формы».

Попробуй лучше так:

@bp.route("/test_js", methods=["GET", "POST"])
@login_required
def test_js():
    if request.method == "POST":
        data = request.get_json()  # Получение данных JSON
        print(f"Received JSON: {data}")  # Логируем для проверки
        return jsonify(data)  # Возвращаем JSON для проверки
    return jsonify({"message": "GET request not supported for this operation."})

А еще судя по всему прикол может быть в том, что у тебя сначала идет POST запрос и данные в нем есть, а потом у тебя идет редирект на эту же ручку и в GET запросе уже нет данных, поэтому в браузере после редиректа ты видишь {}

Поэтому «с новым» кодом «от меня». Ты сможешь увидеть но бэкенде распечатку JSPN-а из POST зарпоса, а потом после редиректа(GET запроса) в браузере ты сможешь увидеть: {"message": "GET request not supported for this operation."}

romanlinux ★★★
()
Последнее исправление: romanlinux (всего исправлений: 1)
Ответ на: комментарий от romanlinux

Весь день экспериментировал с кодом. Думаю, ты прав. Если выводить так

    if request.method == "POST":
        print(f"ЭТО POST!")
        req = request.json
        ids = req['data']

Я в логе вижу сообщение, но дальше в функции, где у меня итерируется data (это список), там пусто.

Такой «хак» тоже не проходит:

    ids = []
    if request.method == "POST":
        for doc_id in request.json['data']:
            ids.append(int(id))
        print(f"{ids=}")
    print(f"{ids=}")
ids=[1, 2]
127.0.0.1 - - [20/Jan/2025 00:52:41] "POST /cart/show/ HTTP/1.1" 200 -
127.0.0.1 - - [20/Jan/2025 00:52:41] "GET /cart/show HTTP/1.1" 308 -
ids=[]

Как это обойти?

Xld
() автор топика

Спасибо всем, кто помог с запросом на js. Дело оказалось не в нем, а как правильно писали, во flask. Теперь ищу решение с ним.

Xld
() автор топика
Ответ на: комментарий от Xld

Ну в целом этот код работает «правильно». На POST запрос ты заслышаешь ему айдишники и он их «печает в консоль», а на GET запрос ты не засылаешь ему этих айдишников и поэтому ему «нечего» печатать в консоль. Тут вопрос в том, что ты хочешь в итоге получить? Какое ТЗ?? А то в данный момент я хз как тебе помочь :(

Потому что все как бы «правильно» работает и я не пойму, что в итоге ты хочешь от «программы»?

romanlinux ★★★
()
Последнее исправление: romanlinux (всего исправлений: 1)
Ответ на: комментарий от Xld

Чтобы просто возвращал через GET, что отправлено через POST.

Ты что норкоман? иди почитай про запросики и как это работает.

  1. Убирай @bp.route("/test_js", methods=["GET", "POST"]) вот тут GET
  2. Возвращай return jsonify(request.form)

И сходи пожалуйста https://flask.palletsprojects.com/en/stable/patterns/javascript/ почитай. вооооот

ggrn ★★★★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.