Converge Lightbox Integration 调用时返回 403
结论
成功获取 session token,只能证明服务器访问 transaction_token 接口时,认证和 IP 白名单配置有效。PayWithConverge.open() 调用的 hpm/initialize 由浏览器发起,还可能校验 token、运行环境和页面的 Origin/Referer。
出现这类 403 时,重点检查以下问题:
- Converge Hosted Payments 未允许当前页面的来源域名或 URL;
- session token 已过期、已使用,或者传入的内容不是纯 token 字符串;
- demo token 与生产环境的 JavaScript/API 混用;
- 创建 token 时使用的 Hosted Payments 配置未启用 Lightbox,或者终端配置受限。
仅把开发服务器的出口 IP 加入白名单,通常还不能满足 Lightbox 的浏览器端授权要求。
首先检查页面来源
transaction_token 是后端请求,Converge 看到的是开发服务器的出口 IP。hpm/initialize 由浏览器发起,通常会携带当前页面的来源信息。
请确认测试页面符合以下条件:
- 通过
http://或https://打开,而不是file://; - 使用固定的主机名和端口;
- 页面域名、协议和端口已按 Converge 账户的要求登记;
- 没有在
localhost、IP 地址和开发域名之间切换; - 反向代理没有改变外部访问地址。
例如,以下地址可能会被视为不同的 Origin:
http://localhost:3000
http://127.0.0.1:3000
https://dev.example.com
https://dev.example.com:8443
如果管理后台没有 Hosted Payments 来源配置入口,需要向 Converge 支持人员确认当前 demo 账户是否允许实际测试页面的 URL,以及该终端是否已启用 Hosted Payments Lightbox。账户版本不同,具体配置名称也可能不同。
确认 demo 环境完全一致
获取 token 和加载 Lightbox JavaScript 必须使用同一环境。既然 token 来自:
https://api.demo.convergepay.com/hosted-payments/transaction_token
页面加载的 PayWithConverge 脚本也应来自 Converge 的 demo 环境。不要把 demo token 传给生产环境脚本,也不要使用生产凭据调用 demo 接口。
可以在浏览器开发者工具的 Network 面板中确认:
- Lightbox 脚本来自
api.demo.convergepay.com; hpm/initialize请求也发往 demo 域名;- 页面没有同时加载生产环境或旧地址的 SDK;
- 控制台中的
PayWithConverge确实由预期脚本提供。
检查 token 的实际内容
ssl_txn_auth_token 必须是刚生成且未经修改的 token。常见错误包括:
- 把整个 JSON 响应放进隐藏字段;
- token 前后带有空格、换行或引号;
- 页面转义改变了 token 内容;
- 重复使用已经初始化过的 token;
- token 生成后等待过久才打开 Lightbox。
客户端至少应清理首尾空白,并阻止重复提交:
let lightboxOpening = false;
function openLightbox() {
const token = document.getElementById("token").value.trim();
if (!token) {
showResult("error", "Missing transaction token");
return;
}
if (lightboxOpening) {
return;
}
lightboxOpening = true;
const paymentFields = {
ssl_txn_auth_token: token
};
const callback = {
onError: function (error) {
lightboxOpening = false;
showResult(
"error",
typeof error === "string" ? error : JSON.stringify(error, null, 2)
);
},
onCancelled: function () {
lightboxOpening = false;
showResult("cancelled", "");
},
onDeclined: function (response) {
lightboxOpening = false;
showResult("declined", JSON.stringify(response, null, 2));
},
onApproval: function (response) {
lightboxOpening = false;
showResult("approval", JSON.stringify(response, null, 2));
}
};
PayWithConverge.open(paymentFields, callback);
}
不要在日志、页面错误信息或截图中公开完整 token。调试时可以只记录 token 长度或经过掩码处理的片段:
console.log("token length:", token.length);
console.log("token preview:", token.slice(0, 6) + "...");
每次重试前都应从服务器重新申请 token,不要用同一个 token 反复调用 open()。
正确处理后端响应
如果由后端调用 transaction_token,需要先明确提取 token,再返回给前端。不要假设上游响应一定是 JSON,应按照实际的 Content-Type 和响应格式处理。
示意代码如下:
const response = await fetch("/api/create-converge-token", {
method: "POST"
});
if (!response.ok) {
throw new Error(`Token request failed: ${response.status}`);
}
const data = await response.json();
const token = String(data.token || "").trim();
if (!token) {
throw new Error("Converge returned an empty token");
}
document.getElementById("token").value = token;
openLightbox();
这里的 data.token 只是应用后端返回格式的示例,不表示 Converge 原始响应一定包含这个字段。后端需要按实际响应格式解析。
根据 Network 信息进一步定位
在开发者工具中打开失败的 hpm/initialize 请求,检查以下内容:
- Request URL;
- Request Headers 中的
Origin和Referer; - 请求负载中的 token 是否为空;
- Response Headers;
- Response body 是否包含错误代码或说明。
可以根据具体表现判断原因:
Origin或Referer与登记地址不一致:修正测试地址,或申请将其加入允许列表;- token 为空或格式异常:修正后端解析和前端赋值;
- 新 token 第一次调用就立即返回 403:检查账户、终端和 Lightbox 功能权限;
- 只有重复调用时失败:将 token 按一次性凭证处理,每次重新生成;
- demo 与生产域名混用:统一环境和凭据。
不要尝试在前端绕过 403
这个 403 来自 Converge 服务端的授权判断,通常无法通过以下方法解决:
- 添加
Access-Control-Allow-Origin; - 使用
mode: "no-cors"; - 禁用浏览器安全策略;
- 修改
hpm-*.js; - 在前端暴露商户凭据并重新申请 token。
如果来源、环境和 token 均已确认无误,但请求仍返回 403,应向 Converge 支持提供以下非敏感信息:
- demo 或 production 环境;
- 商户或终端标识,但不要提供密码、PIN 或完整 token;
- 测试页面的完整 Origin;
- 失败时间和所在时区;
hpm/initialize的 HTTP 状态码;- 响应中的错误标识;
- 从浏览器 Network 导出的请求信息,提交前删除 token 和敏感请求头。
应优先确认两点:Converge 是否只配置了服务器 IP 白名单,却没有允许实际承载 Lightbox 的页面来源;当前终端是否已启用 Hosted Payments Lightbox。
备注:内容仅供参考。
