Android Studio中使用EasyWsdl为SOAP请求添加请求头失败求助
我懂你现在的困境——折腾了OkHTTP、kSoap2,好不容易换成EasyWSDL生成的类能发SOAP请求了,结果卡在加请求头这一步,确实挺烦人的。你用HeaderProperty的思路是对的,但EasyWSDL封装了底层的kSoap2逻辑,直接这么加可能没走对路子,我给你几个可行的方案:
1. 先检查EasyWSDL生成的客户端类有没有内置方法
很多时候EasyWSDL生成的代码会自带设置请求头的方法,比如setHeaders(List<HeaderProperty>)或者addHeader(HeaderProperty)。你可以先翻一下生成的客户端类的代码,比如找类似这样的方法:
public void setHeaders(List<HeaderProperty> headers) { this.transport.setHeaders(headers); }
如果有的话,直接创建HeaderProperty列表传进去就行,不用绕弯路:
// 构建Authorization头 String credentials = "your_username:your_password"; String encodedAuth = android.util.Base64.encodeToString(credentials.getBytes(), android.util.Base64.NO_WRAP); HeaderProperty authHeader = new HeaderProperty("Authorization", "Basic " + encodedAuth); // 添加到列表 List<HeaderProperty> headers = new ArrayList<>(); headers.add(authHeader); // 调用生成类的内置方法 YourGeneratedSoapClient client = new YourGeneratedSoapClient(); client.setHeaders(headers); // 然后正常调用接口方法就行 client.yourSoapMethod(yourRequest);
2. 直接操作底层的kSoap2传输对象
如果生成的类没暴露设置头的方法,那就得拿到底层的HttpTransportSE(kSoap2的核心传输类),在调用请求的时候传入头列表。
首先找到生成类里负责发送请求的代码,通常会有类似这样的逻辑:
private HttpTransportSE transport; private SoapSerializationEnvelope envelope; public YourResponse yourSoapMethod(YourRequest request) throws Exception { envelope.setOutputSoapObject(request); transport.call(SOAP_ACTION, envelope); return (YourResponse) envelope.getResponse(); }
你可以修改这个方法,让它接受List<HeaderProperty>参数,然后在call方法里传入:
// 修改后的方法 public YourResponse yourSoapMethod(YourRequest request, List<HeaderProperty> headers) throws Exception { envelope.setOutputSoapObject(request); // 第三个参数就是请求头列表 transport.call(SOAP_ACTION, envelope, headers); return (YourResponse) envelope.getResponse(); }
然后调用的时候传入你的头列表就行。如果生成的类把transport设成了private,你也可以用反射来获取它(虽然有点hack,但应急能用):
YourGeneratedSoapClient client = new YourGeneratedSoapClient(); // 反射获取private的transport字段 Field transportField = YourGeneratedSoapClient.class.getDeclaredField("transport"); transportField.setAccessible(true); HttpTransportSE transport = (HttpTransportSE) transportField.get(client); // 构建请求头 List<HeaderProperty> headers = new ArrayList<>(); String encodedAuth = android.util.Base64.encodeToString("user:pass".getBytes(), android.util.Base64.NO_WRAP); headers.add(new HeaderProperty("Authorization", "Basic " + encodedAuth)); // 手动调用传输对象的call方法 transport.call(SOAP_ACTION, client.envelope, headers); YourResponse response = (YourResponse) client.envelope.getResponse();
3. 注意Base64编码的坑
这里要特别提醒:别用kSoap2自带的org.kobjects.base64.Base64,用Android系统自带的android.util.Base64,并且一定要加Base64.NO_WRAP参数——很多服务器会因为编码后的字符串带换行符而拒绝解析Authorization头,这个细节很容易踩坑。
4. 用OkHTTP拦截器全局加头(如果底层用OkHTTP)
如果你的EasyWSDL生成的代码用了OkHTTP作为传输层(比如用了OkHttpTransport),那用拦截器全局加请求头会更灵活,不用每次调用都传:
// 创建带拦截器的OkHttpClient OkHttpClient okHttpClient = new OkHttpClient.Builder() .addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request originalRequest = chain.request(); // 添加上Authorization头 Request modifiedRequest = originalRequest.newBuilder() .header("Authorization", "Basic " + yourEncodedAuth) .build(); return chain.proceed(modifiedRequest); } }) .build(); // 把这个client传给EasyWSDL生成的传输对象(如果生成类支持的话) YourGeneratedSoapClient client = new YourGeneratedSoapClient(); client.setOkHttpClient(okHttpClient);
最后几个小提醒
- 区分清楚HTTP请求头和SOAP消息头:你用
HeaderProperty加的是HTTP请求头,如果要加SOAP消息里的<Header>节点,那得往SoapEnvelope里加SoapHeader对象,别搞混了。 - 如果服务器返回401,先检查用户名密码是否正确,编码后的字符串有没有空格(Basic后面必须加空格)。
- 有些SOAP服务还要求
SOAPAction头,确保生成的代码已经正确设置了这个头。
内容的提问来源于stack exchange,提问作者MightyAchmed

