近场通信(NFC)在门禁刷卡、公交支付、智能海报等场景里已经非常普及,但过去网页开发者想要碰一碰NFC标签,几乎只能借助原生App或者中间桥接层。Web NFC API的出现改变了这个局面,它让浏览器直接具备读写NFC标签的能力,只要设备支持NFC并且浏览器实现了该接口,网页就能完成扫描、读取和写入操作。这篇文章会从能力边界讲起,逐步带你完成读写代码,最后讨论实际项目中的坑。

Web NFC API是什么,支持情况如何
Web NFC API是一组基于JavaScript的接口,运行在支持NFC的设备上时,可以让网页与临近的NFC标签(NDEF格式的标签)通信。核心对象是NDEFReader,通过它可以发起扫描、监听标签靠近事件,也可以向可写标签写入NDEF消息。整个流程不需要安装任何插件,也不依赖原生桥接。
需要特别注意的是,Web NFC目前只支持NDEF格式的数据,也就是NFC Data Exchange Format。这意味着那些使用自定义协议的非NDEF标签(比如一些Mifare Classic卡片)是读不到的,浏览器会直接报错。所以在方案设计阶段,就要确认目标标签是NDEF兼容的,否则会白忙一场。
浏览器支持方面,Chrome在桌面端和Android端从89版本开始逐步支持Web NFC,Safari和Firefox长期没有跟进。同时这个API要求页面运行在HTTPS环境(或者localhost调试)下,而且手机必须开启NFC硬件开关。做兼容检测时,可以这样写:
if ('NDEFReader' in window) {
console.log('当前浏览器支持Web NFC');
} else {
console.log('不支持,请降级处理');
}如何扫描并读取NFC标签数据
读取是Web NFC最常用的能力。基本思路是创建一个NDEFReader实例,调用它的scan方法启动扫描,然后监听reading事件获取标签上的数据。下面是一段完整的读取示例:
const reader = new NDEFReader();
async function startScan() {
try {
await reader.scan();
console.log('扫描已启动,请将标签靠近设备');
reader.addEventListener('reading', ({ message, serialNumber }) => {
console.log('标签序列号:', serialNumber);
// 遍历NDEF消息中的每条记录
for (const record of message.records) {
switch (record.recordType) {
case 'text':
const textDecoder = new TextDecoder(record.encoding);
console.log('文本内容:', textDecoder.decode(record.data));
break;
case 'url':
// URL记录同样用TextDecoder解码
console.log('链接:', new TextDecoder().decode(record.data));
break;
default:
console.log('其他类型记录:', record.recordType);
}
}
});
reader.addEventListener('readingerror', () => {
console.log('标签无法读取');
});
} catch (error) {
console.error('启动扫描失败:', error);
}
}这段代码有几个细节值得展开。第一,scan返回的是Promise,只有resolve之后才代表扫描真正启动,所以要用await等待,避免在权限未授予时就绑定事件。第二,一条NDEF消息可以包含多条记录,message.records是数组,实际业务中要考虑多记录的情况,而不是假设只有一条文本。第三,文本记录的编码可能是UTF-8或UTF-16,记录里带了encoding字段,直接传给TextDecoder最稳妥。
另一个容易被忽略的点是生命周期。当用户切换到其他标签页,或者浏览器窗口失焦时,扫描会自动暂停,回来后又自动恢复。这个行为在不同设备上略有差异,建议在UI上给出明确的提示,比如“请保持页面在前台”,避免用户以为功能失效了。
写入NFC标签与权限、错误处理
写入操作同样通过NDEFReader完成,调用write方法即可。写入时必须把设备贴近标签并保持不动,直到Promise结束。写入文本和URL的示例如下:
const writer = new NDEFReader();
async function writeTag() {
try {
// 写入文本,第三个参数指定语言
await writer.write({
records: [
{ recordType: 'text', data: '欢迎扫码体验', lang: 'zh-CN' },
{ recordType: 'url', data: 'https://ipipp.com' }
]
});
console.log('写入成功');
} catch (error) {
if (error.name === 'NotAllowedError') {
console.log('用户拒绝了NFC权限');
} else if (error.name === 'NetworkError') {
console.log('写入失败,请检查标签是否可写、是否贴紧');
}
}
}权限方面,首次调用scan或write时浏览器会弹出授权弹窗,用户允许后才能继续。可以通过navigator.permissions.query提前查询权限状态,在界面上引导用户。需要注意权限是按站点授予的,用户清除站点数据后需要重新授权。
错误处理是落地时最考验耐心的部分。常见错误包括NotAllowedError(权限被拒)、NotSupportedError(设备或浏览器不支持)、NetworkError(通信中断,多半是标签被移开)以及InvalidModificationError(标签处于只读状态)。建议把这些错误映射为友好的中文提示,而不是把原始报错直接抛给用户。另外写入操作最好加上超时控制,比如10秒内没有成功就提示用户重新尝试,防止Promise长时间挂起。
实际应用场景与降级方案
有了读写能力,能做的业务就多了。比如展会签到:把参会者信息写入NDEF标签贴在胸卡上,网页扫描后自动完成签到登记;再比如智能海报场景,海报角落嵌入NFC标签,用户手机一碰直接跳转到活动页面;还有仓储管理,扫描货架标签快速读取库位信息。这些场景的共同特点是交互极短、无需安装App,体验非常顺滑。
当然,兼容性问题不能回避。目前Safari和Firefox并不支持Web NFC,所以必须做特性检测和降级。常见的降级策略是:不支持时展示二维码替代方案,或者提示用户使用支持NFC的浏览器。检测逻辑可以封装成一个工具函数:
function checkNfcSupport() {
if (!('NDEFReader' in window)) {
return { supported: false, reason: '浏览器不支持' };
}
if (!window.isSecureContext) {
return { supported: false, reason: '需要HTTPS环境' };
}
return { supported: true };
}最后提醒一点,Web NFC是“靠近即触发”的交互,从安全角度要防范误触发和重放风险。比如签到场景中,除了读标签序列号,最好结合时间戳、一次性令牌做校验,避免有人复制标签数据刷数据。把NFC当作便捷入口,把校验逻辑留在服务端,这样的架构才经得起实际考验。总体来说,Web NFC API的接口设计简洁,几行代码就能跑通,但要做出稳定好用的近场交互功能,还需要在权限、错误处理和兼容性上多下功夫。
Web NFC API近场通信JavaScript修改时间:2026-09-13 19:00:50