技术文章
轻松实现非接触式交易
人人都知道芯片卡有多让人"后端"头疼。插卡、跺脚、祈祷芯片读取失败,这样就能直接刷磁条了… 好吧,这么说可能有点夸张。但你懂我的意思。标准的"接触式 EMV"让顾客抓狂(也让无数支付应用开发者几近崩溃借酒消愁),因为它速度慢、流程复杂、容错率低。
而非接触式 EMV 彻底改变了这一切。一次"挥卡即走"的交易通常不到 500 毫秒即可完成,而且可以用手机来完成(比掏出实体卡方便多了)。你猜怎么着?对开发者来说也更简单。只需几行代码,就能执行一笔非接触式交易。如果你愿意,还可以完全用 JavaScript 来实现;无需启动 Visual Studio 或 Xcode。没有编译周期,没有链接库,也没有令人头疼的依赖关系。这才叫快速开发!
请看下面这 4 行 JavaScript 代码:
信不信由你,这 4 行代码就能让你使用 ID TECH 提供的任何一款小巧、低成本的 VP3300 系列读卡器(例如上图所示的 VP3300)运行一笔非接触式 EMV 交易。这 4 行代码执行后,你可以将手机(或感应卡)靠近读卡器,读卡器就会发出"嘀"声,启动 NFC 通讯,然后(通过 USB)输出交易数据。
当然,要让这些代码真正起作用,你首先需要安装与 USB 设备通信的 Node 脚本(以及 Node JS 本身) 正如我在上一篇文章中所述。(可在一个压缩包中下载可运行脚本及 Node 本身 此处。)你大概还会想在 Firefox 或 Chrome 中运行上述代码,使用的应用 可在此处获取.
什么是 ViVOpay Explorer?它只是一个非常简单的 HTML 页面,内含一个 JS 控制台和一些预加载命令。该网页由 50 行 HTML 和 400 行 JavaScript 组成(包括我在……中提到的 TLV 解析例程 之前的文章)。当你在 Chrome 或 Firefox 中使用 ViVOpay Explorer 时(不要在 Internet Explorer 中尝试),你会看到类似下图的浏览器页面:
"Console"下方的灰色区域是一个实时 REPL (此处为 jQuery 终端),你可以在其中实时执行任意 JavaScript 代码。在右上角,你会看到几个文本框(显示"http://localhost"和"9901"),旁边有一个 连接 按钮。按下该按钮后,ViVOpay Explorer 会在 127.0.0.1 的 9901 端口上查找 Websocket 连接。页面下半部分是日志区域,各类状态信息(例如 USB 流量读数)会随命令实时显示在此处。
点击下拉菜单旁的小问号会弹出一个简短的帮助面板,告诉你如何使用 ViVOpay Explorer。简而言之,以下是你需要做的:
1. 下载 Node 驱动程序 (11 MB 的 Zip 压缩包),并解压到本地 Windows 计算机。(其中包含一份 node.exe 副本以及脚本和支持文件;所需的一切都在压缩包中。但不要尝试在 Mac 或 Linux 上运行。这是专为 Windows 编译的 Node 版本。)
2. 在解压后的 Zip 文件夹中,找到 start.bat 并运行它。(保持其运行状态,不要关闭其窗口。)这会启动基于 Node 的 USB 通信驱动,同时也会启动一个 Websockets 服务器。
3. 将 ID TECH 的 VP3300 系列读卡器(UniPay III、BTPay Mini 等)插入 USB 接口。Node 驱动会自动检测并连接到该设备。
4. 点击 Connect 按钮(位于上方右侧)。你应能在下方看到这样的消息:"Connected to the driver on port 9901."(已通过 9901 端口连接到驱动程序。)这意味着你的浏览器现在已通过 Websockets 与驱动程序通信,地址为 http://localhost:9901.
5. 从下拉菜单中选择 Ping 读卡器 命令。这会执行一段脚本,对已连接的 USB 设备发送 ping 请求。
如果第 5 步成功,你应该会在主屏幕的 Console 下方看到类似如下的日志响应:
发送:
{
"source":"client"
"data":"5669564f74656368320018010000b3cd"
"type":"raw command"
}
接收:
{
"source":"usb"
"data":"5669564f74656368320018000000fa83″
"type":"data"
}
以下是在 ping 过程中通过 Websockets 向外(发往 USB 设备)和向内(发往浏览器)传递的 JSON 消息。请注意,这些自定义 JSON 对象遵循一个非常简单的结构:包含三个字段,分别为 source、data 和 type。对于出站消息(从浏览器发往驱动程序),source 属性的值应为 "client";data 字段将包含一个十六进制字符串,表示发送到 USB 设备的命令;type 字段则包含 "raw command",以提示驱动程序应将 data 命令直接透传到 USB 设备。
从浏览器向驱动程序发送 JSON 对象(或任何其他消息)非常简单。在浏览器代码中,只需执行: socket.emit( 'echo', myObject )。要从驱动程序接收数据,只需设置一个监听器: socket.on( 'message', myListener ),其中 myListener 可以是匿名函数,例如 function( m ) { log( m ); }。显然,您应当先设置监听器,再向驱动程序发送任何内容。否则,驱动程序可能在您尚未准备好接收响应时就已作出回复。
要让读卡器进入 NFC 模式并读取非接触式卡片或电子钱包,只需发送相应的固件命令(以十六进制字符串形式)即可:
第一行将命令声明为字符串。要了解如何构造此类命令,请参阅您所使用读卡器的技术文档。(您可以从以下位置下载 ID TECH 文档: ID TECH 公共知识库下载页面。)此特定命令包含默认金额 1.00 美元和一个(如今)已过期的日期,因此显然此代码(尽管能够运行!)仅应视为概念验证级别,而非生产级别。如果这是生产代码,您需要将其编写为包含真实金额、实际交易日期等。
将命令传送到读卡器分两步进行:首先,您需要通过 Websockets 以 JSON 对象的形式将其发送给驱动程序;然后由驱动程序将其转发至 USB 读卡器。将命令封装为驱动程序可消费的 JSON 对象非常简单:请参见上方代码的第 2 行和第 3 行。第 4 行将数据对象发送到 socket 上。
再次提醒,在执行上述任何操作之前,您应先为 socket 附加一个监听器(或回调函数),以便处理来自读卡器的响应。这可以非常简单,例如:
还有第二种启动交易的策略。回顾一下我们之前所说的,启动过程分两步:
1. 从浏览器向驱动程序发送消息。
2. 由驱动程序将消息传递给 USB 设备。
所谓"消息",其实就是一长串繁琐的固件十六进制字符串。
本例中的"驱动程序"只是一个运行在 Node 进程空间中的 Node 脚本(约 350 行 JavaScript 代码)。驱动程序的源代码位于 driver 文件夹中。请查找 usb-websocket-shim.js.
您可以很轻松地修改驱动程序代码,使其包含(以字符串形式预先缓存的)用于启动交易的特定固件命令(或一个用于构造该字符串的函数)。这样做可以让您将该固件命令隐藏在自定义的 API 之后,使您的支付应用程序(此处由 ViVOpay Explorer 代表)只需向驱动程序发送一条非常简单(由您自行设计)的消息即可启动交易。
这样做的意义何在?将固件命令隐藏在驱动程序内部的意义何在?
我能想到几个相当不错的理由。
首先,将设备相关的依赖从支付应用程序中剥离出来,放入设备驱动程序中(驱动程序在逻辑上更接近设备),这是合理的。仔细想想,您真的希望支付应用程序对固件命令了如指掌吗?让应用程序摆脱对硬件细节的深度依赖,不是更好吗?应用程序难道不应只关注业务逻辑吗?
其次:将该特定命令下沉到驱动程序中后,您就可以为该命令编写自己的 API,从而为支付应用程序提供一个大幅简化的 API。(请参见下方示例。)
除此之外,还需要考虑作用域的精简。从实践角度看,大多数支付应用程序和销售终端系统的设计方式是:POS 或支付应用程序只需向交易子系统提供交易金额;而交易子系统(与读卡器通信)则返回授权码和可打印的小票信息。敏感的卡片数据从不会到达支付应用程序。
因此在"作用域精简"的情况下,您希望在驱动程序内部加入响应类似如下传入 Websockets 消息的代码:
事实上,这一点已经在我们的 Node 驱动程序中实现了。(请参阅 我之前的帖子 查看驱动程序代码清单。)这意味着,要从支付应用程序(或 ViVOpay Explorer)启动非接触式交易,我们只需要执行:
在 ViVOpay Explorer 中,我已将所有必要代码(包括用于解析交易 TLV 数据并将其显示在屏幕上的回调代码)封装在一个名为以下名称的函数中: startContactlessTransaction().
请记住,如需了解更多关于基于 Node 的驱动程序如何实现 USB 连接的信息,您可以查阅我之前的文章(向下滚动查看链接)。同时也请务必查阅 ID TECH 免费的 下载页面 ,获取更多产品文档、白皮书、SDK 文档等。
如需获取包含 ID TECH 读卡器的评估套件,请随时拨打下方电话联系我们:
