You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OkHttp调用SOAP接口报错"Soap message is invalid!"求助

解决OkHttp结合ksoap2调用Microsoft Dynamics SOAP接口的"Soap message is invalid!"错误

你遇到的核心问题是构建请求体时用错了方法,导致发送给服务器的SOAP内容完全无效。咱们一步步来修正:

1. 错误根源:错误生成SOAP请求体

你代码里这一行是关键错误:

RequestBody body = RequestBody.create(SOAP_MEDIA_TYPE, String.valueOf(envelope.getResponse()));

envelope.getResponse()是用来解析服务器返回的SOAP响应的方法,在发送请求前调用它,得到的要么是空值,要么是无效内容,服务器自然会返回"Soap message is invalid!"。

正确的做法是把ksoap2的SoapSerializationEnvelope序列化成标准的SOAP XML字符串,作为请求体发送。

2. 代码修改步骤

步骤1:添加SOAP请求序列化逻辑

替换原来的请求体构建代码,改成以下内容:

// 将Envelope序列化为SOAP XML字符串
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
XmlSerializer serializer = Xml.newSerializer();
try {
    serializer.setOutput(outputStream, "UTF-8");
    envelope.write(serializer);
    serializer.flush();
} catch (Exception e) {
    Log.e(HttpUtils.class.getSimpleName(), "Failed to serialize SOAP request", e);
    return;
}
String soapRequest = new String(outputStream.toByteArray(), "UTF-8");

// 构建正确的请求体
RequestBody body = RequestBody.create(SOAP_MEDIA_TYPE, soapRequest);

这段代码会把你构建的SoapObject和Envelope转换成符合SOAP规范的XML内容。

步骤2:(可选)修正方法名

你的方法名叫doGetRequest,但实际是发送POST请求,建议改成doSoapPostRequest避免混淆。

步骤3:验证NTLM认证实现

你使用了NTLMAuthenticator,要确保这个类正确实现了OkHttp的Authenticator接口,能处理Dynamics要求的NTLM认证流程。如果认证逻辑有问题,也可能导致请求失败,不过先解决请求体的问题,这是当前最紧急的。

3. 修改后的完整代码示例

package com.demo;

import android.util.Log;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.xmlpull.v1.XmlSerializer;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;

public class HttpUtils {

    private static final MediaType SOAP_MEDIA_TYPE = MediaType.parse("text/xml; charset=utf-8");
    private static final String soap_action = "urn:microsoft-dynamics-schemas/codeunit/HelloWorld:PrintHello";
    private static final String namespace = "urn:microsoft-dynamics-schemas/codeunit/HelloWorld";
    private static final String method_name = "PrintHello";

    public static void doSoapPostRequest() {
        SoapObject soapObject = new SoapObject(namespace, method_name);
        soapObject.addProperty("Username", "ravia");
        soapObject.addProperty("Password", "Ravi@123");
        soapObject.addProperty("Domain", "techcronus");

        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
        envelope.dotNet = true;
        envelope.setOutputSoapObject(soapObject);

        // 序列化Envelope为SOAP XML
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        XmlSerializer serializer = Xml.newSerializer();
        try {
            serializer.setOutput(outputStream, "UTF-8");
            envelope.write(serializer);
            serializer.flush();
        } catch (Exception e) {
            Log.e(HttpUtils.class.getSimpleName(), "SOAP serialization failed", e);
            return;
        }
        String soapRequest = new String(outputStream.toByteArray());

        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .authenticator(new NTLMAuthenticator("ravia", "Ravi@123", "techcronus", ""))
                .build();

        RequestBody body = RequestBody.create(SOAP_MEDIA_TYPE, soapRequest);
        Request request = new Request.Builder()
                .url("http://192.168.1.199:1013/MISReports/WS/Test/Codeunit/HelloWorld")
                .post(body)
                .addHeader("Content-Type", "text/xml; charset=utf-8")
                .addHeader("soapaction", soap_action)
                .build();

        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.e(HttpUtils.class.getSimpleName(), "Request failed: " + e.getMessage());
            }

            @Override
            public void onResponse(Call call, okhttp3.Response response) throws IOException {
                if (response.isSuccessful()) {
                    Log.d(HttpUtils.class.getSimpleName(), "Response: " + response.body().string());
                } else {
                    Log.e(HttpUtils.class.getSimpleName(), "Server error: " + response.body().string());
                }
            }
        });
    }
}

4. 额外检查点

  • 确认namespace、method_name、soap_action完全匹配Dynamics WSDL中的定义,大小写和拼写不能错。
  • 验证接口参数名(Username、Password、Domain)是否和Dynamics端的参数一致。
  • 确保设备能访问http://192.168.1.199:1013这个地址,没有网络权限或者防火墙问题。

内容的提问来源于stack exchange,提问作者Bandish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:22:49