使用wsimport导入的Web Service调用时SOAP Header参数设置求助
解决SOAP Header认证失败的问题
我一眼就看出问题所在了:你当前代码里设置的是HTTP请求头,但你的Web服务要求的是SOAP消息自身的Header区域(也就是你给出的WSDL里<soap:Header>标签下的authUser结构),这两者完全不是同一个东西,所以你的认证参数根本没传到服务期望的位置,自然会返回Authentication Error。
下面给你两种靠谱的解决方案,都是针对SOAP Header的正确设置方式:
方法一:使用wsimport生成的Header类(最规范)
当你用wsimport生成客户端代码时,它应该已经根据WSDL里的authUser结构生成了对应的Java类(比如AuthUser,具体类名可能根据WSDL的命名规则略有调整)。你可以直接通过WSBindingProvider的setRequestHeader方法设置这个对象:
public static void main(String[] args) { System.out.println("Hello world"); WsTest wsTest = new WsTest(); WsTestSoap client = wsTest.getWsTestSoap(); // 转换为WSBindingProvider以便操作SOAP Header WSBindingProvider bindingProvider = (WSBindingProvider) client; // 创建WSDL定义的authUser对象,填充用户名密码 AuthUser authUser = new AuthUser(); authUser.setUserName("xxxxx"); authUser.setPassword("xxxxx"); // 如果服务需要authenticationToken,取消下面注释并赋值 // authUser.setAuthenticationToken("your-token-here"); // 设置SOAP Header,注意命名空间要和WSDL里的完全一致:http://tempuri.org/ bindingProvider.setRequestHeader( "http://tempuri.org/", "authUser", authUser ); try { String re1 = client.authenticateUser(); String re2 = client.existencias("xxxx"); System.out.println(re1); System.out.println(re2); } catch (Exception e) { e.printStackTrace(); } }
方法二:自定义SOAP Handler(手动构建Header)
如果wsimport没有生成对应的AuthUser类,或者你需要更灵活地控制SOAP消息结构,可以自定义一个SOAPHandler来手动构建Header:
第一步:编写Handler类
import javax.xml.namespace.QName; import javax.xml.soap.*; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; import java.util.Set; public class AuthHeaderHandler implements SOAPHandler<SOAPMessageContext> { private final String userName; private final String password; public AuthHeaderHandler(String userName, String password) { this.userName = userName; this.password = password; } @Override public Set<QName> getHeaders() { // 返回我们要处理的Header的QName,对应WSDL里的authUser QName authUserQName = new QName("http://tempuri.org/", "authUser"); return Set.of(authUserQName); } @Override public boolean handleMessage(SOAPMessageContext context) { // 只处理 outbound(发送出去的)消息 Boolean isOutbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); if (isOutbound) { try { SOAPMessage soapMsg = context.getMessage(); SOAPEnvelope envelope = soapMsg.getSOAPPart().getEnvelope(); SOAPHeader header = envelope.getHeader(); // 如果Header不存在,创建一个 if (header == null) { header = envelope.addHeader(); } // 构建authUser元素,注意命名空间和前缀要和WSDL一致 QName authUserQName = new QName("http://tempuri.org/", "authUser", "tem"); SOAPElement authUserElement = header.addChildElement(authUserQName); // 添加userName子元素 SOAPElement userNameElem = authUserElement.addChildElement("userName", "tem"); userNameElem.setTextContent(userName); // 添加password子元素 SOAPElement passwordElem = authUserElement.addChildElement("password", "tem"); passwordElem.setTextContent(password); // 可选:如果需要authenticationToken,取消下面注释 // SOAPElement tokenElem = authUserElement.addChildElement("authenticationToken", "tem"); // tokenElem.setTextContent("your-token"); soapMsg.saveChanges(); } catch (SOAPException e) { e.printStackTrace(); return false; } } return true; } @Override public boolean handleFault(SOAPMessageContext context) { return true; } @Override public void close(MessageContext context) { // 无需额外清理,留空即可 } }
第二步:在客户端代码中添加Handler
import java.util.ArrayList; import java.util.List; import javax.xml.ws.handler.Handler; public static void main(String[] args) { System.out.println("Hello world"); WsTest wsTest = new WsTest(); WsTestSoap client = wsTest.getWsTestSoap(); WSBindingProvider bindingProvider = (WSBindingProvider) client; // 创建Handler实例并添加到客户端的Handler链中 List<Handler> handlerChain = new ArrayList<>(); handlerChain.add(new AuthHeaderHandler("xxxxx", "xxxxx")); bindingProvider.getBinding().setHandlerChain(handlerChain); try { String re1 = client.authenticateUser(); String re2 = client.existencias("xxxx"); System.out.println(re1); System.out.println(re2); } catch (Exception e) { e.printStackTrace(); } }
为什么原来的代码会失败?
你之前用request.put(MessageContext.HTTP_REQUEST_HEADERS, headers)设置的是HTTP协议级别的请求头(比如我们常见的Authorization、Content-Type这类),但你的服务要求的是SOAP消息体内部的soap:Header标签里的结构化数据,这是SOAP协议自身的Header,和HTTP头完全是两个层面的东西,所以服务根本没收到你的认证参数,自然返回认证错误。
内容的提问来源于stack exchange,提问作者Isaac Mena
相关产品推荐
相关产品推荐

