表单默认提交行为导致请求被取消

起因是最近接手的一个前端管理系统项目,这是个19年的老项目,技术栈就不必多说了,jquery+layui ,我看了直接傻眼,我曼波是个后端开发啊😭😭😭!!!终究是活成了自己最讨厌的样子。话又说回来,成为一名全栈er感觉也挺爽的,只是我不想接触这么一坨大杂烩的时代遗物。

问题

打开模态框填写表单数据,然后点击按钮提交表单发起请求时发现预检OPTION 请求通过了,但是真正的请求却被取消了,随后整个页面自动刷新了,模态框也被关闭但没有触发任何回调函数弹出提示框。这个问题其实很基础,但我作为一名半路出家的前端,对这种场景没什么经验。

image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 监听提交按钮点击事件
$('#submitAfterSale').on('click', function() {
var formElement = $('#addAfterSaleForm')[0];
if (formElement) {
var formData = new FormData(formElement);
var formObject = {};
formData.forEach((value, key) => {
formObject[key] = value;
});
admin.req({
url: setter.sendUrl + '/biz/order/after',
type: 'post',
contentType: 'application/json',
data: JSON.stringify(formObject),
done: function(res) {
if (res.code === 200) {
layer.msg('提交成功', {icon: 1, time: 2000});
layer.closeAll();
} else {
layer.msg('提交失败', {icon: 2, time: 2000});
}
},
});
}
});

我一开始甚至都没注意到这个请求是被取消了,还在想是不是跨域出了问题,,然后当我注意到这个东西的时候,我就google了一下,终于找到了出问题的原因。问题就出这个post请求还没有完成,这个按钮的dom元素就已经被删除了,所以请求也被浏览器取消了。

至于为什么会出现这种情况,这就得说说button 这个组件了。在html页面中,buttontype 属性有三个值,分别是buttonsubmitreset ,当type 属性设置为submit 时,点击按钮就会触发表单的默认提交行为。

所以这个场景下,点击提交按钮会触发两个请求,一个是表单的默认提交行为,它提交的URL由当前form 标签的actoin 属性设置(例如<form id="addAfterSaleForm" action="/submit" method="post">),如果没有设置,,则默认提交到当前页面的URL。另一个请求则是由JS脚本触发,向后端地址发起的请求。但是由于第一个提交到当前页面的请求已经完成触发页面刷新并关闭了模态框,而第二个请求是由ajax发起的异步请求,这就导致真正的请求还没有完成,刚刚触发请求的dom元素(即提交按钮)却已经被删除了,最后请求也就被浏览器取消了。

解决办法

解决办法倒是很简单,有两种办法。

一种是阻止表单的默认提交行为。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 监听提交按钮点击事件
$('#submitAfterSale').on('click', function() {
// 阻止表单的默认提交行为
event.preventDefault();
var formElement = $('#addAfterSaleForm')[0];
if (formElement) {
var formData = new FormData(formElement);
var formObject = {};
formData.forEach((value, key) => {
formObject[key] = value;
});
admin.req({
url: setter.sendUrl + '/biz/order/after',
type: 'post',
contentType: 'application/json',
data: JSON.stringify(formObject),
done: function(res) {
if (res.code === 200) {
layer.msg('提交成功', {icon: 1, time: 2000});
layer.closeAll();
} else {
layer.msg('提交失败', {icon: 2, time: 2000});
}
},
});
}
});

而另一种就是将buttontype 属性设置为普通的按钮button

1
<button id="submitAfterSale" class="layui-btn" type="button" lay-filter="submitAfterSale">提交</button>

参考资料

https://juejin.cn/post/6844904045480509447

https://developer.aliyun.com/article/1152493