Ingenico .net SDK 调用 API 时出现 Unauthorized 和连接关闭异常
结论
这些异常首先表明 TLS 握手失败,通常不是 hosted checkout 的请求参数有问题。Ingenico Sandbox 端点一般要求 TLS 1.2。如果应用运行在较旧的 .NET Framework 或操作系统上,或者代理、防火墙正在进行 HTTPS 检查,服务器可能会在返回 HTTP 响应前关闭连接,从而出现以下错误:
The underlying connection was closedAuthentication failed because the remote party has closed the transport streamAn unexpected error occurred on a send
应先解决 TLS 或网络问题,再处理实际的 HTTP 401 Unauthorized。能够收到 401,说明 TLS 连接已经建立,此时需要检查 API Key、签名、merchantId、系统时间以及环境配置是否匹配。
先启用 TLS 1.2
对于旧版 .NET Framework,可以在创建 Ingenico SDK Client 前显式启用 TLS 1.2:
using System.Net;
internal static class Program
{
private static void Main()
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
// 在此之后创建并调用 Ingenico SDK Client
}
}
不过,下面这种赋值方式会覆盖系统已经启用的其他安全协议:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
如果应用还要访问其他服务,更稳妥的写法是保留现有协议并加入 TLS 1.2:
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
在较新的 .NET、.NET Core 或 .NET 5+ 中,TLS 协议通常由操作系统和 HttpClient 自动协商,一般不需要强制指定版本。如果这些运行时仍然无法完成握手,应检查操作系统补丁、证书链、公司代理和防火墙。
检查 SDK 端点配置
SDK 的 API endpoint 应包含协议,不要自行拼接 /v1/{merchantId}:
https://eu.sandbox.api-ingenico.com
完整路径通常由 SDK 根据 merchantId 和所调用的方法生成。不要配置成:
eu.sandbox.api-ingenico.com/v1/{merchantId}
以下代码展示了各项配置之间的关系。Ingenico .NET SDK 不同版本的类名和方法签名可能不同,请以当前 NuGet 包附带的 API 和示例为准:
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
var configuration = new CommunicatorConfiguration()
.WithApiEndpoint(new Uri("https://eu.sandbox.api-ingenico.com"))
.WithApiKeyId(apiKeyId)
.WithSecretApiKey(secretApiKey)
.WithIntegrator("YourCompany");
using (var client = Factory.CreateClient(configuration))
{
var result = client
.Merchant(merchantId)
.Services()
.TestConnection();
Console.WriteLine(result);
}
这段代码用于说明配置方式,不保证其中的类型名称适用于所有 SDK 版本。如果编译器提示某个成员不存在,请查看已安装版本的 IntelliSense、NuGet 包说明或示例工程,不要混用其他版本文档中的调用方式。
如果返回 401 Unauthorized
收到 HTTP 401 后,排查重点应从 TLS 转到认证配置:
-
确认 API Key ID 和 Secret API Key 配套
重新复制 Sandbox Console 中生成的凭据,检查是否带入了首尾空格、换行或引号。Secret 通常只在创建时完整显示。如果无法确认,可以重新生成一组 Sandbox 凭据。
-
确认凭据和 endpoint 属于同一环境
Sandbox 凭据只能用于 Sandbox endpoint。生产环境的 API Key、merchantId 通常不能与 Sandbox 混用。
-
确认 merchantId 正确
merchantId 不是账户登录名,也不一定等于组织或公司编号。它必须是对应 API 凭据有权访问的商户编号。
-
不要手工添加或修改签名头
SDK 会根据 HTTP 方法、路径、日期和内容类型等信息生成认证签名。代理改写请求头、重复添加
Authorization,或者在签名生成后修改 URL,都可能导致认证失败。 -
检查机器时间
请求签名通常包含时间信息。系统时间或时区偏差过大,可能导致服务器拒绝认证。请确保操作系统已经通过 NTP 正确同步时间。
-
确认 API Key 的权限和状态
新建的 API Key 可能尚未获得所需权限,或者没有关联当前 merchantId。具体权限名称可能因 Ingenico/Worldline 平台版本和账户配置而异,需要在 Sandbox Console 中核实。
区分传输异常和认证异常
这两类错误需要沿着不同方向排查:
| 现象 | 所处阶段 | 优先检查 |
|---|---|---|
remote party has closed the transport stream | TLS 握手 | TLS 1.2、证书、代理、防火墙、操作系统 |
An unexpected error occurred on a send,没有 HTTP 状态码 | 网络或 TLS | 内层异常、代理、DNS、TLS |
HTTP 401 Unauthorized | 已进入 API 认证 | API Key、Secret、merchantId、签名、系统时间 |
HTTP 403 Forbidden | 已识别身份但无权限 | 商户关联、API 权限、账户状态 |
HTTP 400 Bad Request | 请求已到达 API | hosted checkout 请求字段及格式 |
排查时,不要只记录最外层的 An error occurred while sending the request。应输出包含所有 inner exception 的完整异常:
try
{
// Ingenico SDK call
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.ToString());
}
ex.ToString() 通常比只打印 ex.Message 更有用,因为 TLS 错误的实际原因经常位于多层 InnerException 中。
网络和代理排查
如果启用 TLS 1.2 后仍然失败,可以依次检查以下项目:
- 在同一台机器上确认
eu.sandbox.api-ingenico.com:443能否正常解析并建立 HTTPS 连接。 - 检查公司代理、防火墙或安全软件是否拦截了该域名。
- 如果代理执行 TLS inspection,确认代理签发证书所使用的根证书已经安装在运行账户可访问的信任存储中。
- 确认应用进程能够使用系统代理。浏览器可以打开该域名,不代表 Console 应用使用了相同的代理。
- 更新 Windows、.NET Framework 和根证书。
- 在不经过公司代理的网络或另一台较新的机器上运行同一测试,以缩小问题范围。
- 不要关闭证书验证来处理握手问题,否则会留下严重的支付安全风险。
创建 hosted checkout 前的建议
确认 testconnection 成功后,再调用:
POST /v1/{merchantId}/hostedcheckouts
创建 hosted checkout 时,还需要提供 SDK 要求的请求对象,例如订单金额、货币、客户信息,以及支付成功或取消后的返回地址。字段结构会随 SDK/API 版本变化,请直接使用当前 SDK 中的请求模型,不要从旧示例中复制 JSON。
建议按以下顺序验证:
- 确认
testconnection能够成功返回。 - 使用最小合法请求创建 hosted checkout。
- 记录 Ingenico 返回的 HTTP 状态码、错误 ID、错误代码和 request ID。
- 确认金额使用 API 要求的最小货币单位。例如,对某些货币而言,
100表示1.00。具体规则以对应货币和当前 API 文档为准。 - Sandbox 测试通过后,再单独配置生产 endpoint 和生产凭据。不要在代码中复用或硬编码 Secret。
文档和社区资源
Ingenico 支付平台后来经历过品牌和产品线调整,部分资料可能使用 Worldline、Ingenico Connect 或 GlobalCollect 等名称。搜索时可以组合使用以下关键词:
Ingenico Connect .NET SDK
Worldline Online Payments .NET SDK
Ingenico testconnection TLS 1.2
Ingenico hostedcheckouts
优先查看当前账户后台链接的开发者文档、对应 NuGet 包的版本说明和 SDK 源码示例。社区博客可以帮助理解流程,但认证签名、endpoint 和请求模型仍应以当前官方 SDK/API 文档为准。
联系技术支持时,最好同时提供以下信息:
- endpoint 和环境名称,但不要提供 Secret;
- merchantId 的脱敏值;
- SDK 包名及版本;
- .NET 与操作系统版本;
- 完整异常堆栈;
- HTTP 状态码和响应体;
- 服务端返回的 request ID 或 correlation ID;
- 是否经过代理或 TLS inspection。
最先应尝试的是在旧版 .NET Framework 程序启动时启用 TLS 1.2。连接建立后如果仍然返回 401 Unauthorized,再逐项检查 Sandbox API 凭据、merchantId、系统时间和权限配置。
备注:内容仅供参考。
