Java客户端如何使用自定义绑定属性访问SOAP服务端
应用.NET自定义SOAP绑定到Java客户端的解决方案
核心配置拆解
你提供的.NET自定义绑定包含两个必须匹配的核心规则:
- 安全模式:UserNameOverTransport,即SOAP头携带用户名密码凭证,传输层必须使用HTTPS加密
- 消息编码:Soap12WSAddressingAugust2004,即使用SOAP1.2协议,WS-Addressing规范版本为2004年8月版(命名空间为
http://schemas.xmlsoap.org/ws/2004/08/addressing)
实现步骤(基于JAX-WS标准,兼容IDEA默认生成的代码)
1. 配置消息版本与WS-Addressing
// 替换为你生成的服务类、端口类,获取端口实例 YourService service = new YourService(); YourPort port = service.getMyBindingPort(); BindingProvider bindingProvider = (BindingProvider) port; SOAPBinding soapBinding = (SOAPBinding) bindingProvider.getBinding(); // 启用SOAP1.2协议 soapBinding.setSOAPVersion(SOAPBinding.SOAP12HTTP_BINDING); Map<String, Object> requestContext = bindingProvider.getRequestContext(); // 指定WS-Addressing 2004/08版本命名空间,默认版本为2005/08,不匹配会导致服务端无响应 requestContext.put("javax.xml.ws.addressing.namespace", "http://schemas.xmlsoap.org/ws/2004/08/addressing"); // 填写服务端实际请求地址 requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "https://你的服务地址");
如果你的代码是用Apache CXF生成的,WS-Addressing配置方式如下:
Client client = ClientProxy.getClient(port); client.getFeatures().add(new org.apache.cxf.ws.addressing.AddressingFeature("http://schemas.xmlsoap.org/ws/2004/08/addressing"));
2. 配置UserNameOverTransport认证
自定义SOAP处理器添加WS-Security用户名密码头:
- 编写自定义处理器类
public class UsernameTokenHandler implements SOAPHandler<SOAPMessageContext> { private final String username; private final String password; public UsernameTokenHandler(String username, String password) { this.username = username; this.password = password; } @Override public Set<QName> getHeaders() { QName securityQname = new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security"); return Collections.singleton(securityQname); } @Override public boolean handleMessage(SOAPMessageContext context) { Boolean isOutbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); if (isOutbound) { try { SOAPEnvelope envelope = context.getMessage().getSOAPPart().getEnvelope(); SOAPHeader header = envelope.getHeader() == null ? envelope.addHeader() : envelope.getHeader(); // 添加WS-Security头 SOAPElement securityEle = header.addChildElement("Security", "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); securityEle.addAttribute(new QName("mustUnderstand"), "1"); // 添加用户名密码令牌 SOAPElement usernameTokenEle = securityEle.addChildElement("UsernameToken", "wsse"); usernameTokenEle.addChildElement("Username", "wsse").setTextContent(username); SOAPElement passwordEle = usernameTokenEle.addChildElement("Password", "wsse"); passwordEle.addAttribute(new QName("Type"), "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"); passwordEle.setTextContent(password); context.getMessage().saveChanges(); } catch (SOAPException e) { throw new RuntimeException("添加认证头失败", e); } } return true; } @Override public boolean handleFault(SOAPMessageContext context) { return true; } @Override public void close(MessageContext context) {} }
- 把处理器绑定到端口
List<Handler> handlerChain = soapBinding.getHandlerChain(); handlerChain.add(new UsernameTokenHandler("你的实际用户名", "你的实际密码")); soapBinding.setHandlerChain(handlerChain);
3. 必要校验项
- 必须使用HTTPS协议请求服务端,HTTP请求会被.NET服务端直接拦截,无返回
- 如果服务端使用自签名SSL证书,需要提前将证书导入Java运行时的信任库,避免SSL握手失败
- 开启报文日志排查问题,在requestContext中添加如下配置即可打印完整请求响应报文:
requestContext.put("com.sun.xml.ws.transport.http.client.HttpTransportPipe.dump", true);
内容的提问来源于stack exchange,提问作者wexyglareb
相关产品推荐
相关产品推荐

