如何使用 jQuery submit 发送 FormData?
结论
jQuery.submit() 不能接收或发送 FormData 对象,它只用于绑定或触发表单的提交事件。
如果要通过 AJAX 发送已经创建的 formData,需要在 submit 事件中调用 $.ajax(),同时设置:
processData: false,
contentType: false
如果支付网关要求浏览器跳转,并通过普通表单发起 POST 请求,就不应使用 FormData 和 AJAX。此时可以创建隐藏字段,再调用原生的 form.submit()。
使用 AJAX 发送 FormData
假设需要提交的表单是 #frmPayment,可以这样写:
<form id="frmPayment">
<button type="submit">支付</button>
</form>
var formData;
$.ajax({
url: "/MyController/MyAction/",
type: "POST",
data: {
MyVariable: objData
},
success: function (data) {
if (data === "Error") {
return;
}
var payment = data;
formData = new FormData();
formData.append("key", gtKFFx);
formData.append("tsnId", payment.TransantionId);
formData.append("amount", billAmount);
formData.append("productinfo", "Test");
formData.append("firstname", custName);
formData.append("email", "chetan.gupta21@gmail.com");
formData.append("surl", "http://google.com");
formData.append("furl", "http://facebook.com");
formData.append("hash", payment.TransactionHash);
$("#frmPayment").trigger("submit");
},
error: function (xhr) {
console.log(xhr);
}
});
$("#frmPayment").on("submit", function (e) {
e.preventDefault();
if (!formData) {
return;
}
$.ajax({
url: "https://payment-gateway.example.com/pay",
type: "POST",
data: formData,
processData: false,
contentType: false,
success: function (response) {
console.log(response);
},
error: function (xhr) {
console.log(xhr);
}
});
});
processData: false 会阻止 jQuery 把 FormData 转换成查询字符串。contentType: false 会让浏览器自动生成带有正确 boundary 的 multipart/form-data 请求头。
不要手动设置:
contentType: "multipart/form-data"
手动设置后,请求头中会缺少浏览器生成的 boundary,服务器可能因此无法解析请求体。
submit 事件最好在页面初始化时绑定一次。不要在第一个 AJAX 请求每次成功后重复绑定,否则再次执行这段流程时,可能会同时触发多个提交处理器。
支付网关需要页面跳转时
不少支付网关不适合通过 AJAX 调用。它们通常要求浏览器提交普通 HTML 表单,再跳转到网关页面。遇到这种情况,可以把参数添加为隐藏字段:
<form
id="frmPayment"
method="post"
action="https://payment-gateway.example.com/pay">
</form>
function addHiddenField(form, name, value) {
$("<input>", {
type: "hidden",
name: name,
value: value
}).appendTo(form);
}
$.ajax({
url: "/MyController/MyAction/",
type: "POST",
data: {
MyVariable: objData
},
success: function (data) {
if (data === "Error") {
return;
}
var payment = data;
var $form = $("#frmPayment");
addHiddenField($form, "key", gtKFFx);
addHiddenField($form, "tsnId", payment.TransantionId);
addHiddenField($form, "amount", billAmount);
addHiddenField($form, "productinfo", "Test");
addHiddenField($form, "firstname", custName);
addHiddenField($form, "email", "chetan.gupta21@gmail.com");
addHiddenField($form, "surl", "http://google.com");
addHiddenField($form, "furl", "http://facebook.com");
addHiddenField($form, "hash", payment.TransactionHash);
$form[0].submit();
},
error: function (xhr) {
console.log(xhr);
}
});
这里调用:
$form[0].submit();
是为了使用浏览器原生的表单提交方式。浏览器会直接向表单的 action 地址发送请求,并跳转到支付页面。
如何选择
目标接口明确支持 AJAX,且 CORS 已正确配置时,可以使用 FormData + $.ajax()。
如果支付网关要求用户跳转、显示支付页面或完成第三方认证,应使用隐藏字段和普通表单 POST。具体采用哪种方式,以支付网关的接口文档为准。
交易金额、订单号、签名和回调地址等重要参数,不能只在前端生成或校验。支付签名应由服务端生成,支付结果也要通过服务端回调再次验证,不能只根据浏览器的跳转结果更新订单状态。
备注:内容仅供参考。
