带身份验证Header的SOAP WebService调用失败求助
错误信息
expected: START_TAG {http://schemas.xmlsoap.org/soap/envelope/}Envelope (position:START_TAG @2:44 in java.io.InputStreamReader@54570a0)
未获取到任何响应。
核心问题分析
这个错误说明服务端返回的是HTML内容(如错误页面、权限验证页面),而非标准SOAP响应。核心原因是身份验证请求格式不合法,导致服务端拒绝处理并返回错误页面。
代码修复点
1. WS-Security Header格式完全错误(最关键)
你的getHeaderElement()生成的Header不符合WS-Security UsernameToken标准规范,修正如下:
public static Element[] getHeaderElement() { // 修正带空格的命名空间,使用标准WS-Security命名空间 String WSS_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; Element[] header = new Element[1]; // 创建Security根元素 header[0] = new Element().createElement(WSS_NS, "Security"); header[0].setAttribute(null, "mustUnderstand", "1"); // 创建UsernameToken容器元素 Element usernameToken = new Element().createElement(WSS_NS, "UsernameToken"); header[0].addChild(Node.ELEMENT, usernameToken); // 标准Username元素 Element username = new Element().createElement(WSS_NS, "Username"); username.addChild(Node.TEXT, USER_NAME); // 用TEXT类型传递用户名,而非IGNORABLE_WHITESPACE usernameToken.addChild(Node.ELEMENT, username); // 标准Password元素,取消注释并添加密码值 Element pass = new Element().createElement(WSS_NS, "Password"); pass.setAttribute(null, "Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"); pass.addChild(Node.TEXT, PASSWORD); usernameToken.addChild(Node.ELEMENT, pass); return header; }
错误点说明:
- 原代码用
null命名空间,服务端无法识别身份验证元素 - 错误使用
USER_NAME/PASSWORD常量作为元素名,标准元素名应为Username/Password - 用户名用
IGNORABLE_WHITESPACE传递,服务端无法读取有效内容 - Security元素命名空间存在空格,导致命名空间无效
- 密码内容被注释,未传递有效凭证
2. 适配.NET WebService配置
你的服务URL是.asmx格式(ASP.NET WebService),需将envelope.dotNet设为true:
envelope.dotNet = true; // 原代码设为false,不符合.NET SOAP格式要求
3. 修复HTTPS传输问题
如果服务端使用HTTPS,建议使用HttpsTransportSE替代HttpTransportSE,测试阶段可临时添加证书信任(生产环境禁用):
HttpsTransportSE androidHttpTransport = new HttpsTransportSE(URL); // 测试用:信任所有证书 androidHttpTransport.setHostnameVerifier((hostname, session) -> true);
额外排查步骤
查看实际请求/响应内容
利用已开启的debug模式,调用失败后打印请求和响应详情,定位服务端返回的HTML错误原因:System.out.println("请求内容:" + androidHttpTransport.requestDump); System.out.println("响应内容:" + androidHttpTransport.responseDump);用Postman验证基准请求
先在Postman中构造符合要求的SOAP请求(带正确WS-Security Header),确认能获取正常响应后,再对比代码生成的请求内容找差异。确认SOAP Action正确性
部分.NET服务要求SOAP Action为完整URL+方法名,如https://example.com/and/service.asmx/method,可替换原SOAP_ACTION常量测试。
内容的提问来源于stack exchange,提问作者mohamadjamous

