PAYATHON 2026

MS SoapClient 出现 WSDLReader error '80020009'

支付小周

明确结论

这个错误表示:MS SoapClient 无法连接到 WSDL 地址,因此没有获得可解析的 XML 内容。

问题可能出在 SSL/TLS,但仅凭 80020009 不能断定是 SSL 故障。DNS 解析失败、端口阻断、代理配置不当、WSDL 地址错误、身份验证失败、证书验证失败,或者服务器不支持旧客户端使用的 TLS 协议,都可能导致同样的错误。

linenumber 0, lineposition 0 是一条重要线索。它通常说明解析器尚未收到 WSDL 文档,故障发生在建立连接或获取响应时,并非 WSDL XML 某一行存在语法错误。

先检查 WSDL 地址

确认传给 MSSoapInit 的是实际 WSDL 地址,而不是支付页面、接口首页或只接受 SOAP POST 的服务端点。例如:

<%
Dim client
Set client = Server.CreateObject("MSSOAP.SoapClient30")

client.MSSoapInit "https://payment.example.com/service.asmx?WSDL"
%>

需要检查:

  • URL 是否完整,是否包含正确的 http:// 或 https://。
  • 服务是否要求 ?WSDL 或指定的 WSDL 文件路径。
  • 请求是否发生了 HTTP 到 HTTPS 跳转。
  • URL 返回的是 WSDL XML,还是登录页、错误页或网关拦截页面。
  • WSDL 是否引用了其他无法访问的 XSD 或 WSDL 文件。

不要只在开发电脑的浏览器里测试。ASP 代码运行在 IIS 服务器上,因此必须从 IIS 所在服务器 验证该地址是否可达。

单独测试 HTTPS 连接

可以暂时绕过 SoapClient,使用 ServerXMLHTTP 获取 WSDL。这样更容易看到具体的连接状态:

<%
Option Explicit

Dim http, wsdlUrl
wsdlUrl = "https://payment.example.com/service.asmx?WSDL"

On Error Resume Next

Set http = Server.CreateObject("MSXML2.ServerXMLHTTP.6.0")
http.open "GET", wsdlUrl, False
http.send

If Err.Number <> 0 Then
    Response.Write "Connection error: " & Server.HTMLEncode(Err.Description)
    Err.Clear
Else
    Response.Write "HTTP status: " & http.status & "<br>"
    Response.Write Server.HTMLEncode(Left(http.responseText, 1000))
End If

Set http = Nothing
On Error GoTo 0
%>

根据测试结果继续排查:

  • 出现连接错误时,检查 TLS、证书、DNS、防火墙和代理。
  • 返回 401 或 403,说明服务需要认证,或者拒绝当前服务器访问。
  • 返回 404,说明 WSDL 地址不正确。
  • 返回 301 或 302,说明存在重定向,而旧版 SOAP 组件未必能正确处理。
  • 返回 200,但内容是 HTML,说明该地址返回的不是 WSDL。
  • 返回有效 XML,说明网络连接基本正常,接下来应检查 WSDL 兼容性和 SoapClient 初始化参数。

不要在生产环境直接输出完整响应,其中可能含有内部地址、认证信息或支付接口细节。

如果确实是 SSL/TLS 问题

MS SOAP Toolkit 和早期 Windows 组件已经非常陈旧。现代支付网关通常会禁用 SSL 3.0、TLS 1.0 和 TLS 1.1,只接受 TLS 1.2 或更高版本。如果运行 Classic ASP 的 Windows/IIS 环境过旧,客户端可能无法与服务器协商出双方都支持的协议。

可以依次检查:

  1. Windows 是否支持并启用了支付网关要求的 TLS 版本。
  2. 服务器是否安装了当前系统更新。
  3. HTTPS 证书链是否完整,根证书和中间证书是否受信任。
  4. 证书域名是否与访问 URL 一致。
  5. 系统日期和时间是否正确。
  6. IIS 进程使用的账户能否访问网络和证书吊销检查地址。
  7. 出站 443 端口是否被防火墙或安全软件阻止。
  8. 当前网络是否要求使用代理,而服务端组件没有配置代理。

不要用忽略证书错误的方式处理支付接口故障。证书校验失败通常说明地址、证书链或服务器配置需要修复。

检查代理和运行账户

浏览器能打开 WSDL,不代表 Classic ASP 也能打开。浏览器使用当前登录用户的代理设置和凭据,而 IIS 应用程序池运行在另一个账户下。

如果网络要求使用 HTTP 代理,可以通过 ServerXMLHTTP 验证:

<%
Dim http
Set http = Server.CreateObject("MSXML2.ServerXMLHTTP.6.0")

' SXH_PROXY_SET_PROXY = 2
http.setProxy 2, "proxy.example.com:8080"

http.open "GET", "https://payment.example.com/service.asmx?WSDL", False
http.send

Response.Write http.status
Set http = Nothing
%>

代理地址和认证方式必须按照实际网络环境配置。不要把代理密码或支付网关密钥直接写入可公开访问的 ASP 文件。

捕获 SoapClient 的具体错误

连接测试成功后,再初始化 SoapClient:

<%
Option Explicit

Dim soap, wsdlUrl
wsdlUrl = "https://payment.example.com/service.asmx?WSDL"

On Error Resume Next

Set soap = Server.CreateObject("MSSOAP.SoapClient30")
soap.MSSoapInit wsdlUrl

If Err.Number <> 0 Then
    Response.Write "Number: " & Hex(Err.Number) & "<br>"
    Response.Write "Source: " & Server.HTMLEncode(Err.Source) & "<br>"
    Response.Write "Description: " & Server.HTMLEncode(Err.Description)
    Err.Clear
Else
    Response.Write "WSDL initialized successfully."
End If

Set soap = Nothing
On Error GoTo 0
%>

如果 ServerXMLHTTP.6.0 能够下载 WSDL,但 MSSoapInit 仍然失败,可以继续检查:

  • WSDL 是否导入了外部 XSD。
  • 导入地址是否为内网地址、相对地址或已经失效。
  • WSDL 使用的 SOAP/WSDL 特性是否超出 MS SOAP Toolkit 的支持范围。
  • 服务是否要求客户端证书或特殊认证。
  • WSDL 是否包含旧组件无法识别的编码或绑定定义。

更可靠的处理方案

MS SOAP Toolkit 已经过时,不适合继续作为支付系统的新依赖。如果支付网关允许直接发送 SOAP XML,在 Classic ASP 中使用 MSXML2.ServerXMLHTTP.6.0 调用服务端点通常更稳妥。调用时需要自行设置 Content-Type、SOAPAction 和请求正文:

<%
Option Explicit

Dim http, endpoint, soapAction, requestXml
endpoint = "https://payment.example.com/service"
soapAction = "urn:CreatePayment"

requestXml = _
    "<?xml version=""1.0"" encoding=""utf-8""?>" & _
    "<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">" & _
      "<soap:Body>" & _
        "<CreatePayment xmlns=""urn:payment"">" & _
          "<Amount>100.00</Amount>" & _
        "</CreatePayment>" & _
      "</soap:Body>" & _
    "</soap:Envelope>"

Set http = Server.CreateObject("MSXML2.ServerXMLHTTP.6.0")
http.open "POST", endpoint, False
http.setRequestHeader "Content-Type", "text/xml; charset=utf-8"
http.setRequestHeader "SOAPAction", """" & soapAction & """"
http.send requestXml

Response.Write "HTTP status: " & http.status

Set http = Nothing
%>

代码中的端点、命名空间、操作名、SOAPAction 和 XML 结构都只是示例,必须以支付网关提供的 WSDL 和接口文档为准。SOAP 1.2 使用的 Content-Type 与 SOAP 1.1 不同,不能直接套用。

注意事项

调用支付接口时还要注意:

  • 不要在页面中输出密钥、签名原文、银行卡数据或完整的服务响应。
  • 为连接和响应设置合理的超时时间。
  • 记录 HTTP 状态码以及经过脱敏的错误信息。
  • 金额应使用支付网关规定的小数格式和币种。
  • 不要只根据 HTTP 200 判断支付成功,还应解析业务返回码并验证签名。
  • 如果网关要求双向 TLS,仅安装服务器证书还不够,必须按照接口要求提供客户端证书。

排查时不应只盯着 ASP 报错所在的第 23 行,而要确认该行使用的 WSDL URL 能否由 IIS 服务器成功获取。先用 ServerXMLHTTP.6.0 检查连接和响应内容,就能进一步判断问题出在 TLS 或证书、网络访问、身份认证,还是 WSDL 与旧版 SoapClient 的兼容性。

备注:内容仅供参考。