Сохранять ту же веб-страницу после запроса POST на iOS устройствах (Django отправка 204 ответа о состоянии) - PullRequest
0 голосов
/ 29 марта 2020

Мой Django проект имеет ряд кнопок на веб-странице, которые выполняют POST-запросы к основному view.py, который, в свою очередь, обрабатывает действие и возвращает ответ 204 No content. Результаты действия отображаются асинхронно позже на веб-странице (во время генерирования ответа нет ничего нового для отображения). В любом браузере, отличном от iOS, ответ 204 работает нормально, и веб-страница остается в браузере, как и ожидалось от RF C 7231 . К сожалению, все браузеры на основе iOS, которые я пробовал (Safari, Firefox, Chrome), переходят на пустую страницу после POST, а это не то, что мне нужно (см. этот вопрос) . Очевидно, это давняя ошибка в WebKit .

Есть ли способ добиться того же самого во всех браузерах? ie. Нажмите кнопку POST, веб-страница останется как есть, изменения появятся позже. Я посмотрел на это , но не уверен, что это действительно то, что я после. Изменение кода ответа возможно, но я не вижу приемлемой альтернативы, которая бы не отклонялась от текущей страницы. Мое хакерское исправление состоит в том, чтобы перезагрузить всю страницу для устройства iOS, но это перемещает страницу, если пользователь прокручивал ее ранее, поэтому выглядит довольно дерзко.

1 Ответ

0 голосов
/ 13 апреля 2020

Решение для этого содержится в этот вопрос и ответ Терри . Плюс некоторая другая информация об обработке CSRF защиты в Django.

Краткий ответ - переопределить отправку обычной формы с помощью event.preventDefault() в вашей собственной функции onsubmit для каждой формы. , Затем выполните POST асинхронно с JQuery. Это избавляет сервер от необходимости возвращать HttpResponse со статусом 204 или что-то действительно, кроме пустого JsonResponse.

На моей веб-странице есть несколько форм, поэтому мне не назначено ни одной функции для каждой кнопки, как в приведенном выше связанном ответе, но некоторые из них меняют поведение отдельных кнопок. Также для Django добавлено рассмотрение включения токена CSRF в запрос POST.

Так, например, некоторые html с двумя кнопками;

<form id="form-a" onsubmit="submit_form_a(event)">{% csrf_token %}
    <input type="hidden" name="button-a" value="some_value_for_a">
    <button type="submit" class="w3-button">Button A</button>
</form>

<form id="form-z" onsubmit="submit_form_z(event)">{% csrf_token %}
    <input type="hidden" name="button-z" value="some_value_for_z">
    <button type="submit" class="w3-button">Button Z</button>
</form>

Затем Javascript, когда первая форма отправляет обратный вызов, например, отключает кнопку;

function submit_form_a(e){
    e.preventDefault();
    var url = "/main/a"
    var formData = $(e.target).serialize();
    var btn = $(e.target).find("button");
    btn.prop("disabled", true);
    myPost(url, formData);
}

И вторая отправляет обратный вызов, который выполняет некоторую анимацию, используя превосходный W3. CSS;

function submit_form_z(e){
   e.preventDefault();
   var url = "/main/z"
   var formData = $(e.target).serialize();
   var btn = $(e.target).find("button");
   btn.toggleClass("w3-animate-fading").toggleClass("w3-text-red")
   myPost(url, formData);
}

Оба этих сценария вызывают общий сценарий mypost, который устанавливает заголовок XMLHttpResponse с маркером CSRF, затем отправляет;

// Make sure any AJAX POST requests are not going off-site. Prevents
// leaking the CSRF token.

function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } 

function myPost(url, data) {
    var csrftoken = $("[name=csrfmiddlewaretoken]").val();
    // Set the header on the AJAX POST request with the CSRF token
    $.ajaxSetup({beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }});
    $.post(url, data);
}

Вернемся к стороне Django views.py, посмотрите на данные <input> из формы и сделайте то, что вам нужно сделать. Я только что обнаружил на iOS, что сами кнопки не включаются в данные формы POST, как это происходит с другими платформами, что делает необходимым ввод элементов скрытого текста;

if request.is_ajax() and request.method == 'POST':
    if 'button-a' in request.POST:
        # do something for A
    elif 'button-z' in request.POST:
      # do something for Z
    return JsonResponse({})

И вуаля! Кнопки могут быть нажаты, фоновые вещи происходят, и страница не движется. Вы можете вернуть что-то, кроме пустого ответа JSON, и обработать его обратно в виде обратных вызовов, таких как повторное включение кнопки, но мне это не нужно. См. Ранее связанный ответ для деталей там.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...