如何解决调用SOAP接口时出现的XmlPullParserException?
解决SOAP调用返回JSON导致的XmlPullParserException问题
你这明显是踩了个“协议不匹配”的坑:你用ksoap2按照SOAP协议发送请求,但接口实际返回的是纯JSON格式数据,而ksoap2的HttpTransportSE默认会把响应当作SOAP XML来解析,这就直接触发了XmlPullParserException——它预期看到XML标签,结果拿到的是JSON的{符号,自然直接报错崩溃。
问题根源
你的代码里,androidHttpTransportSE.call(SOAP_ACTION, envelope)这一行会自动尝试将服务器响应解析为SOAP Envelope,但服务器返回的是JSON,完全不符合SOAP规范的XML结构,所以解析过程直接失败,根本执行不到后续处理JSON的代码段。
解决方案:绕过ksoap2的自动解析,手动获取原始响应
我们需要跳过ksoap2的XML解析步骤,直接获取服务器返回的原始JSON字符串,再自行处理JSON解析。这里提供两种可行的实现方式:
方式1:修改HttpTransportSE的使用逻辑,获取原始响应
利用HttpTransportSE的底层连接能力,跳过自动解析步骤,直接读取响应流:
@Override protected String doInBackground(String... params) { String result = ""; try { // 构建SOAP请求体 SoapObject request = new SoapObject(SOAP_NAMESPACE, SOAP_METHOD); request.addProperty("labcode", mLabCode.getText().toString()); request.addProperty("username", mUserName.getText().toString()); request.addProperty("pass", mPasswordView.getText().toString()); SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); envelope.setOutputSoapObject(request); envelope.dotNet = true; HttpTransportSE androidHttpTransportSE = new HttpTransportSE(URL); // 发送请求但跳过自动解析(第三个参数设为false) androidHttpTransportSE.call(SOAP_ACTION, envelope, false); // 读取原始响应流 InputStream inputStream = androidHttpTransportSE.getServiceConnection().getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { sb.append(line); } result = sb.toString(); reader.close(); inputStream.close(); // 处理JSON(注意:根据报错日志,返回的是JSONObject而非JSONArray) Log.e("Test Result", result); try { JSONObject jsonObject = new JSONObject(result); strStatusID = jsonObject.getString("Flag"); labCode = jsonObject.getString("LabCode"); userName = jsonObject.getString("Username"); Log.e("Flag", strStatusID); } catch (JSONException e) { e.printStackTrace(); } } catch (Exception e) { e.printStackTrace(); } return result; }
方式2:直接用原生HttpURLConnection发送SOAP请求
如果觉得ksoap2的封装限制太多,也可以用原生HttpURLConnection手动构造SOAP XML请求,再读取JSON响应:
@Override protected String doInBackground(String... params) { String result = ""; try { // 手动构造SOAP请求XML String soapRequest = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns=\"" + SOAP_NAMESPACE + "\">" + "<soap:Body>" + "<ns:" + SOAP_METHOD + ">" + "<ns:labcode>" + mLabCode.getText().toString() + "</ns:labcode>" + "<ns:username>" + mUserName.getText().toString() + "</ns:username>" + "<ns:pass>" + mPasswordView.getText().toString() + "</ns:pass>" + "</ns:" + SOAP_METHOD + ">" + "</soap:Body>" + "</soap:Envelope>"; URL url = new URL(URL); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "text/xml; charset=utf-8"); conn.setRequestProperty("SOAPAction", SOAP_ACTION); conn.setDoOutput(true); // 发送SOAP请求 OutputStream os = conn.getOutputStream(); os.write(soapRequest.getBytes("UTF-8")); os.flush(); os.close(); // 读取响应内容 InputStream inputStream = conn.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { sb.append(line); } result = sb.toString(); reader.close(); inputStream.close(); conn.disconnect(); // 解析JSON Log.e("Test Result", result); try { JSONObject jsonObject = new JSONObject(result); strStatusID = jsonObject.getString("Flag"); labCode = jsonObject.getString("LabCode"); userName = jsonObject.getString("Username"); Log.e("Flag", strStatusID); } catch (JSONException e) { e.printStackTrace(); } } catch (Exception e) { e.printStackTrace(); } return result; }
额外提醒
- 确认JSON格式:从报错日志看,服务器返回的是
{ "Flag": 1, ...}这种单个对象,不是JSON数组,所以原来代码里用JSONArray解析会触发JSONException,记得改成JSONObject。 - 提前验证响应:建议先用Postman之类的工具发送相同的SOAP请求,确认服务器返回的确实是纯JSON,而非包裹在SOAP Envelope里的JSON内容。
内容的提问来源于stack exchange,提问作者Afsal .Kritisoft
相关产品推荐
相关产品推荐

