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 环境过旧,客户端可能无法与服务器协商出双方都支持的协议。
可以依次检查:
- Windows 是否支持并启用了支付网关要求的 TLS 版本。
- 服务器是否安装了当前系统更新。
- HTTPS 证书链是否完整,根证书和中间证书是否受信任。
- 证书域名是否与访问 URL 一致。
- 系统日期和时间是否正确。
- IIS 进程使用的账户能否访问网络和证书吊销检查地址。
- 出站
443端口是否被防火墙或安全软件阻止。 - 当前网络是否要求使用代理,而服务端组件没有配置代理。
不要用忽略证书错误的方式处理支付接口故障。证书校验失败通常说明地址、证书链或服务器配置需要修复。
检查代理和运行账户
浏览器能打开 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 的兼容性。
备注:内容仅供参考。
