为了账号安全,请及时绑定邮箱和手机立即绑定

在 iOS 设备上发出 POST 请求后保持相同的网页(Django 发送 204 状态响应)

在 iOS 设备上发出 POST 请求后保持相同的网页(Django 发送 204 状态响应)

慕婉清6462132 2023-10-17 19:57:59
我的 Django 项目在网页上有许多按钮,它们向主程序发送 POST 请求,主程序view.py依次处理操作并返回204 No content响应。操作的结果稍后会异步显示在网页上(生成响应时,没有任何新内容可显示)。在任何基于非 iOS 的浏览器上,204 响应都可以正常工作,并且网页保留在浏览器中,正如RFC 7231所期望的那样。不幸的是,我尝试过的所有基于 iOS 的浏览器(Safari、Firefox、Chrome)都会在 POST 后导航到空白页面,这不是我想要的(请参阅此问题)。显然这是WebKit 中长期存在的错误。有什么方法可以在所有浏览器上实现相同的效果吗?IE。单击按钮,POST,网页保持原样,更改稍后出现。我看过这个,但不确定这真的是我想要的。更改响应代码是可能的,但我没有看到不离开当前页面的可行替代方案。我目前的黑客修复是为 iOS 设备重新加载整个页面,但是如果用户之前向下滚动,这会移动页面,所以看起来很卡顿。
查看完整描述

1 回答

?
qq_花开花谢_0

TA贡献1835条经验 获得超7个赞

event.preventDefault() 简短的答案是在您自己的函数中为每个表单覆盖常规表单提交onsubmit。然后使用 JQuery 异步执行 POST。这避免了服务器必须返回状态为 204 的 HttpResponse,或者除了空的 JsonResponse 之外的任何其他内容。

我的网页上有多个表单,因此我没有为每个按钮分配单个功能,如上面链接的答案中所示,但有几个可以更改单个按钮的行为。另外,对于 Django,还需要考虑在 POST 请求中包含 CSRF 令牌。

例如,一些带有两个按钮的 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,该脚本使用 CSRF 令牌设置 XMLHttpResponse 标头,然后将其发布;


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

}

回到 Djangoviews.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 响应之外的其他内容,并在表单回调中处理它,例如重新启用按钮,但我不需要这样做。有关详细信息,请参阅之前链接的答案。


查看完整回答
反对 回复 2023-10-17
  • 1 回答
  • 0 关注
  • 77 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信