如何创建支持支付信息 autofill 的 HTML form?
结论
支付信息自动填充主要依赖标准的 autocomplete token,同时也会受到浏览器字段识别规则的影响。要让银行卡号、持卡人姓名和有效期得到正确识别,需要为每个 <input> 设置准确的 autocomplete、name 和 type 等属性,并采用语义清楚的表单结构。
cc-name 表示银行卡上显示的完整持卡人姓名。如果页面将姓和名拆成两个输入框,应分别使用:
cc-given-name:名cc-family-name:姓
不要再调用 form.requestAutocomplete()。这个实验性 API 已被废弃,现代浏览器通常不再提供。支付信息下拉菜单是否出现,取决于用户保存的银行卡、页面安全性、用户操作以及浏览器内部策略,JavaScript 无法强制打开。
推荐写法
如果页面只需要一个“持卡人姓名”输入框,可以采用以下结构:
<form action="/payment" method="post" autocomplete="on">
<div>
<label for="card-number">银行卡号</label>
<input
id="card-number"
name="card-number"
type="text"
inputmode="numeric"
autocomplete="cc-number"
required
>
</div>
<div>
<label for="cardholder-name">持卡人姓名</label>
<input
id="cardholder-name"
name="cardholder-name"
type="text"
autocomplete="cc-name"
required
>
</div>
<div>
<label for="expiry-month">有效期月份</label>
<input
id="expiry-month"
name="expiry-month"
type="text"
inputmode="numeric"
autocomplete="cc-exp-month"
placeholder="MM"
required
>
</div>
<div>
<label for="expiry-year">有效期年份</label>
<input
id="expiry-year"
name="expiry-year"
type="text"
inputmode="numeric"
autocomplete="cc-exp-year"
placeholder="YYYY"
required
>
</div>
<div>
<label for="security-code">安全码</label>
<input
id="security-code"
name="security-code"
type="text"
inputmode="numeric"
autocomplete="cc-csc"
required
>
</div>
<button type="submit">支付</button>
</form>
如果业务要求将姓名拆开,则应使用更具体的 token:
<div>
<label for="given-name">名</label>
<input
id="given-name"
name="given-name"
type="text"
autocomplete="cc-given-name"
required
>
</div>
<div>
<label for="family-name">姓</label>
<input
id="family-name"
name="family-name"
type="text"
autocomplete="cc-family-name"
required
>
</div>
不过在实际使用中,单个 cc-name 字段通常兼容性更好。许多浏览器保存的是完整的持卡人姓名,而不是分开的姓和名。如果支付接口允许,建议优先使用单字段设计。
有效期也可以使用单字段
银行卡有效期既可以拆分为月份和年份,也可以放在一个字段中:
<label for="card-expiry">有效期</label>
<input
id="card-expiry"
name="card-expiry"
type="text"
inputmode="numeric"
autocomplete="cc-exp"
placeholder="MM/YY"
required
>
cc-exp 表示完整有效期,cc-exp-month 和 cc-exp-year 分别表示月份和年份。具体采用哪种形式,需要与支付服务商要求的数据格式一致。
浏览器填充的年份可能是两位或四位,例如 28 或 2028。提交前需要解析并验证,不能只依赖 maxlength 或占位文本。
为什么只写 cc-name 仍可能无效
autocomplete 只是提供给浏览器的语义提示,并非强制命令。浏览器还会判断:
- 页面是否通过 HTTPS 加载;
- 用户是否在浏览器中保存了银行卡;
- 用户是否启用了付款方式自动填充;
- 字段是否可见、可编辑;
<label>、name、id和附近文本是否符合支付场景;- 字段是否位于跨域
<iframe>中; - 页面是否存在可疑行为或处于不安全的上下文;
- 浏览器、操作系统、地区和企业策略是否允许填充支付信息。
因此,有些网站即使没有完整设置 autocomplete 属性,仍能触发自动填充。浏览器也会根据字段名称、标签、布局和历史数据进行启发式识别。不过,这类识别并不是稳定的接口,不能作为实现依据。
表单实现时的注意事项
不要为银行卡字段设置 autocomplete="off"。部分浏览器可能会忽略该值,但它仍会让字段的语义变得不够明确。
也不要省略 name 属性。标准 token 主要写在 autocomplete 中,但清楚的 name 也有助于浏览器识别字段,例如:
name="cardholder-name"
name="card-number"
name="expiry-month"
不要用普通 <div> 模拟输入框,也不要隐藏真正的 <input>,再自行同步其中的内容。浏览器通常需要直接识别并填写可见的原生表单控件,才能完成支付信息自动填充。
银行卡号不适合使用 type="number",因为它可能引入数字步进、格式限制和前导零处理等问题。更合适的写法是:
type="text" inputmode="numeric" autocomplete="cc-number"
自动填充也不能代替表单验证。即使字段由浏览器填写,服务端仍须验证卡号、有效期和其他支付参数。银行卡数据还应交给合规的支付服务商处理,避免自己的服务器直接接触原始卡号和安全码。
JavaScript 不负责触发自动填充
不要继续使用以下代码:
form.requestAutocomplete();
event.preventDefault();
requestAutocomplete() 已经不是可靠的 Web API。正常情况下,只需处理表单提交:
form.addEventListener("submit", (event) => {
event.preventDefault();
// 验证数据,并交给支付服务商的 SDK 或支付接口处理。
});
event.preventDefault() 只能阻止表单的默认提交行为,无法让浏览器显示银行卡选择菜单。自动填充菜单通常会在用户聚焦或点击银行卡字段时,由浏览器自行显示。
比较稳妥的做法是使用 HTTPS、原生 <form> 和 <input>,为每个字段配置准确的 autocomplete token,并优先用单个 cc-name 字段保存完整的持卡人姓名。支付信息下拉菜单最终是否出现,仍由浏览器和用户设置决定,页面无法强制触发。
备注:内容仅供参考。
