【问题标题】:iOS Safari fails to send form data via AJAXiOS Safari 无法通过 AJAX 发送表单数据
【发布时间】:2018-07-05 23:10:36
【问题描述】:

我正在尝试使用 JavaScript 通过 Ajax 提交表单。它适用于 Browserstack 中的 IE、Firefox、Chrome 和 iOS,但不适用于 iOS Simulator 或真正的 iOS 设备或桌面 Safari。

我试过XMLHttpRequest onloadXMLHttpRequest onreadystatechange,都没有被触发。据我所知request.open('POST', url, true); 不起作用。 console.log('2'); 也永远不会被触发。

我添加了这个用于调试:

request.send(data);
console.log(request);
setTimeout(function(){ console.log(request); }, 3000);

它们在 Safari 中都返回 readyState: 1,在其他浏览器中第一个返回 readyState: 1 而第二个返回 readyState: 4 符合预期。

这是我的代码精简到基本要素:

$('.ajax-form').submit(function(event) {
  var form = event.target;
  var data = new FormData(form);
  var request = new XMLHttpRequest();
  var method = form.getAttribute("method");
  var action = form.getAttribute("action");
  var url = window.location.href
  request.open('POST', url, true);
  request.setRequestHeader("X-Requested-With", "XMLHttpRequest");
  request.setRequestHeader("HTTP_X_REQUESTED_WITH", "XMLHttpRequest");
  request.setRequestHeader("pragma", "no-cache");
  console.log('1');
  request.onreadystatechange = function() {
    console.log('2');
    if (request.readyState === 4 && request.status === 200) {
      var response = JSON.parse(request.response);

      if (response.success && response.finished) {
        // Go to selected success page
        window.location.href = $(form).find('[name="formReturnUrl"]').attr('value');

      } else if (response.errors || response.formErrors) {
        // Deal with errors
      }
    }
  };

  request.send(data);
  console.log(request);
  setTimeout(function() {
    console.log(request);
  }, 3000);
  event.preventDefault();
});

我所有的 iOS 测试都是在 Safari 中的 iOS 11 上进行的。我读过一些关于 iOS 很奇怪的文章,但我还没有找到适合我的解决方案。我做错了什么?

【问题讨论】:

  • 我不知道为什么会这样,但我建议您尝试$.post(),因为您已经在使用 jQuery。
  • 感谢您的想法,但 jQuery Ajax 没有从我的 CMS(运行 Freeform 的工艺)正确返回表单错误数据。我正在尝试对 Ajax 使用纯 JavaScript,因为它在我的环境中完美运行,除了在 iOS Safari 中......还有其他想法吗?

标签: javascript ios ajax forms


【解决方案1】:

解决了。感谢@mxcoder 为我指明了正确的方向。

Safari(桌面和 iOS)在使用空文件字段创建 FormData 时存在错误。我通过在创建 FormData 之前禁用空文件字段然后立即重新启用它们来解决这个问题,以便在提交 Ajax 后可以重用表单。

我把var data = new FormData(form);改成了这个:

// Disable empty file fields before submitting.
if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {
    var $inputs = $('input[type="file"]:not([disabled])', form);
    $inputs.each(function(_, input) {
        if (input.files.length > 0) return
        $(input).prop('disabled', true);
    });
}

var data = new FormData(form);

// Re-enable empty file fields after creating FormData.
if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {
    $inputs.prop('disabled', false);
}
  1. 如果浏览器是 Safari,请禁用空的 <input type="file"> 元素
  2. 创建表单数据
  3. 如果浏览器是 Safari,请重新启用空的 <input type="file"> 元素。这允许在成功提交或纠正错误后重复使用表单。

【讨论】:

    【解决方案2】:

    有趣的问题,Safari 有时候确实很棘手。

    我还没有适合您的解决方案,但您可以尝试以下方法:

    1. 尽量不要使用 FormData,也许 iOS 还不能很好地与 XHR + FormData 配合使用,这可能是一个值得报告的错误!
    2. 能否分享请求和响应的正文和标头?也许服务器端的某些东西无法处理 iOS 请求,再次,可能是一些错误的标头。

    【讨论】:

    • 1.我对 JavaScript Ajax 有点陌生。我会怎么做呢? 2.点击提交按钮后,wi-fi图标旁边的小数据风车会旋转,但网​​络检查器从不显示任何网络活动。似乎桌面 Safari 也有同样的问题。
    • 在 1 上,您现在可以尝试一些简单的方法,例如:xhr.send("foo=bar&lorem=ipsum"); 只需注释掉 FormData 的用法,以验证您是否被 iOS 错误阻止。
    • 这似乎行得通。现在我应该如何替换 FormData?
    • 好吧,你总是可以使用 jQuery serialize 方法,它接受一个表单并以表单值作为 URL 参数吐出一个字符串。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-25
    • 2016-04-20
    • 2016-01-21
    • 1970-01-01
    • 1970-01-01
    • 2015-02-13
    相关资源
    最近更新 更多