Spring Boot实现SOAP客户端调用报错Invalid Content-Type:text/html如何解决
问题修复方案
根因说明
你遇到的错误本质是请求格式完全不符合服务端预期,服务端返回PHP错误页面(Content-Type为text/html),才触发解析报错,具体问题点:
setDefaultUri配置错误:该参数需要填SOAP服务的实际接口地址,不是WSDL地址- 请求根节点错误:你当前用
loginDataClass作为Body下的根节点,服务端要求的根节点是login - 命名空间错误:根节点的命名空间填了SOAP编码的地址,实际需要用服务端业务命名空间
https://xpartner.net.pl/xpartner/ - 参数结构错误:服务端要求
login节点下嵌套obj节点,再放账号密码参数,你当前直接把账号密码放在loginDataClass下
分步修改代码
1. 修正配置类的默认地址
client.setDefaultUri填写服务端接口地址https://xpartner.net.pl/wsdlSoapServ2.php,修正后的配置类代码:
@Configuration public class XpartnerConfig { @Bean public Jaxb2Marshaller marshaller() { Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); marshaller.setContextPath("com.autokonto.pl.xpartner"); return marshaller; } // 可选配置:强制指定请求Content-Type为text/xml @Bean public SaajSoapMessageFactory soapMessageFactory() { SaajSoapMessageFactory factory = new SaajSoapMessageFactory(); factory.setSoapVersion(SoapVersion.SOAP_11); return factory; } @Bean public XpartnerClient xpartnerClient(Jaxb2Marshaller marshaller, SaajSoapMessageFactory soapMessageFactory) { XpartnerClient client = new XpartnerClient(); // 这里填服务端接口地址,不是WSDL地址 client.setDefaultUri("https://xpartner.net.pl/wsdlSoapServ2.php"); client.setMarshaller(marshaller); client.setUnmarshaller(marshaller); client.setMessageFactory(soapMessageFactory); return client; } }
2. 修正请求结构与命名空间
你之前直接将LoginDataClass作为根节点发送,需要先包装成服务端要求的login节点,且正确设置命名空间:
@Slf4j @Service @RequiredArgsConstructor public class XpartnerApiService { // 修正QName:命名空间改为业务命名空间,节点名改为login private final static javax.xml.namespace.QName _LOGIN_QNAME = new javax.xml.namespace.QName("https://xpartner.net.pl/xpartner/", "login"); @Value("${xpartner.login}") private String login; @Value("${xpartner.password}") private String password; LoginResultClass loginResultClass; private final XpartnerClient xpartnerClient; @PostConstruct void login() { log.info("log in xpartnerClient"); ObjectFactory objectFactory = new ObjectFactory(); // 构造账号密码对象 LoginDataClass data = objectFactory.createLoginDataClass(); data.setLogin(login); data.setPass(password); // 构造obj节点,嵌套账号密码 JAXBElement<LoginDataClass> objElement = new JAXBElement<>(new QName("https://xpartner.net.pl/xpartner/", "obj"), LoginDataClass.class, data); // 构造根节点login,嵌套obj JAXBElement<JAXBElement> loginElement = new JAXBElement<>(_LOGIN_QNAME, JAXBElement.class, objElement); this.loginResultClass = xpartnerClient.login(loginElement); log.info("LOGGING RESULT" + loginResultClass.isLoginResult()); } }
3. 客户端代码无需修改,保持原有逻辑即可
@Slf4j public class XpartnerClient extends WebServiceGatewaySupport { public LoginResultClass login(JAXBElement<?> loginRequest) { LoginResultClass response = (LoginResultClass) getWebServiceTemplate().marshalSendAndReceive(loginRequest); return response; } }
额外说明
如果JAXB插件已经根据WSDL生成了Login请求类,直接用该类构造请求即可,不需要手动包装QName,逻辑会更简洁。上述通用方案适配你当前已生成的类结构,调整后请求格式就会和你预期的一致。
内容的提问来源于stack exchange,提问作者valik
相关产品推荐
相关产品推荐

