我一直在努力尝试使用ksoap2为Android构建正确的SOAP请求数小时而没有运气。理想的请求如下:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<AuthorizationToken xmlns="http://www.avectra.com/2005/">
<Token>string</Token>
</AuthorizationToken>
</soap:Header>
<soap:Body>
<ExecuteMethod xmlns="http://www.avectra.com/2005/">
<serviceName>string</serviceName>
<methodName>string</methodName>
<parameters>
<Parameter>
<Name>string</Name>
<Value>string</Value>
</Parameter>
</parameters>
</ExecuteMethod>
</soap:Body>
</soap:Envelope>
我使用以下代码生成我的请求:
SoapObject request = new SoapObject(NAMESPACE, METHOD);
request.addProperty("serviceName", SERVICENAME);
request.addProperty("methodName", METHODNAME);
SoapObject nestedParameters = new SoapObject(NAMESPACE, "parameters");
SoapObject param = new SoapObject(NAMESPACE, "Parameter");
param.addProperty("Name", name);
param.addProperty("Value", value);
nestedParameters.addSoapObject(param);
request.addSoapObject(nestedParameters);
SoapSerializationEnvelope envelope =
new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
envelope.dotNet = true;
envelope.implicitTypes = true;
envelope.headerOut = new Element[1];
Element header = new Element().createElement(NAMESPACE, "AuthorizationToken");
Element token = new Element().createElement(NAMESPACE, "Token");
token.addChild(Node.TEXT, this.AUTH_TOKEN);
header.addChild(Node.ELEMENT, token);
envelope.headerOut[0] = header;
ksoap2正在构建的是:
<v:Envelope xmlns:i="http://www.w3.org/1999/XMLSchema-instance" xmlns:d="http://www.w3.org/1999/XMLSchema" xmlns:c="http://schemas.xmlsoap.org/soap/encoding/" xmlns:v="http://schemas.xmlsoap.org/soap/envelope/">
<v:Header>
<n0:AuthorizationToken xmlns:n0="http://www.avectra.com/2005/">
<n0:Token>string</n0:Token>
</n0:AuthorizationToken>
</v:Header>
<v:Body>
<ExecuteMethod xmlns="http://www.avectra.com/2005/" id="o0" c:root="1">
<serviceName>AHAWebServices</serviceName>
<methodName>MemberDirectory</methodName>
<parameters i:type="n1:parameters" xmlns:n1="http://www.avectra.com/2005/">
<Parameter i:type="n1:Parameter">
<Name>string</Name>
<Value>string</Value>
</Parameter>
</parameters>
</ExecuteMethod>
</v:Body>
</v:Envelope>
我有一种感觉问题是在带有n0前缀的标题中,但我不知道如何摆脱它们。我通过将implicitTypes设置为true将其从正文中删除,但我找不到类似的标题设置。我是SOAP的新手,所以非常感谢任何其他建议。有谁知道如何解决这个问题?
答案 0 :(得分:5)
使用KSOAP时这对我有用
SoapObject request = new SoapObject(WEBSERVICE_NAMESPACE, methodName);
if(null != parameterMap && !parameterMap.isEmpty()){
for(Entry<String, String> entry: parameterMap.entrySet()){
request.addProperty(entry.getKey(), entry.getValue());
}
}
// Declare the version of the SOAP request
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.implicitTypes = true;
envelope.dotNet = true;
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(ApplicationConstants.WEBSERVICE_WSDL_URL);
// this is the actual part that will call the webservice
try {
androidHttpTransport.debug = true;
androidHttpTransport.call(soapActionUrl, envelope);
String ss = androidHttpTransport.responseDump;
// Get the SoapResult from the envelope body.
Log.d(TAG, "request: " + androidHttpTransport.requestDump);
Log.d(TAG, "response: "+ androidHttpTransport.responseDump);
SoapObject result = (SoapObject) envelope.getResponse();
Log.d("soap response", "" + result);
} catch (IOException e) {
Log.e(TAG, "IOException", e);
}
注:
androidHttpTransport.debug = true;
在我的案例中解决了这个问题。引起了我的注意,但无法解释为什么设置debug true有助于解决问题。
为什么需要使用ksoap? 只需将SOAP请求的静态方作为String,将值附加到静态部分,最后可以获得完整的SOAP请求。最后使用HTTP方法发送您的帖子请求。
没有额外的JAR
此外,ksoap还有像OOM这样的大型回复等问题。
您可以使用以下代码
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map.Entry;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import android.util.Log;
public final class SOAPRequest{
private static final String TAG = "SOAPRequest";
private static final String TAG_SOAP_HEADER_START = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Header>";
private static final String TAG_AUTHORIZATION_START = "<AuthorizationToken xmlns=\"http://www.avectra.com/2005/\">";
private static final String TAG_TOKEN_START = "<TOKEN>";
private static final String TAG_TOKEN_END = "</TOKEN>";
private static final String TAG_AUTORIZATION_END = "</AuthorizationToken>";
private static final String TAG_SOAPHEADER_END = "</soap:Header>";
private static final String TAG_SOAP_BODY_START = "<soap:Body>";
private static final String TAG_PARAM_NAME_START = "<Name>";
private static final String TAG_PARAM_NAME_END = "</Name>";
private static final String TAG_PARAM_VALUE_START = "<Value>";
private static final String TAG_PARAM_VALUE_END = "</Value>";
private static final String TAG_METHOD_START = "<methodName>";
private static final String TAG_METHOD_END = "</methodName>";
private static final String TAG_SERVICE_START = "<serviceName>";
private static final String TAG_SERVICE_END = "</serviceName>";
private static final String TAG_PARAMS_START = "<parameters><Parameter>";
private static final String TAG_EXE_METHOD_START = "<ExecuteMethod xmlns=\"http://www.avectra.com/2005/\">";
private static final String TAG_SOAP_REQ_END = "</Parameter></parameters></ExecuteMethod></soap:Body></soap:Envelope>";
/**
* Constructor intentionally made private
*/
private SOAPRequest() {
}
/**
* Builds a SOAP request with the specified value
* @param token Value of token
* @param serviceName Value of servicename
* @param methodName Value of methodName
* @param paramsMap Collection of parameters as set of name value pair which needs to be sent
* @return the complete soap request
*/
public static String buildRequest(String token, String serviceName, String methodName, HashMap<String, String> paramsMap){
StringBuilder requestBuilder = new StringBuilder(TAG_SOAP_HEADER_START);
requestBuilder.append(TAG_AUTHORIZATION_START);
requestBuilder.append(TAG_TOKEN_START);
requestBuilder.append(token);
requestBuilder.append(TAG_TOKEN_END);
requestBuilder.append(TAG_AUTORIZATION_END);
requestBuilder.append(TAG_SOAPHEADER_END);
requestBuilder.append(TAG_SOAP_BODY_START);
requestBuilder.append(TAG_EXE_METHOD_START);
requestBuilder.append(TAG_SERVICE_START);
requestBuilder.append(serviceName);
requestBuilder.append(TAG_SERVICE_END);
requestBuilder.append(TAG_METHOD_START);
requestBuilder.append(methodName);
requestBuilder.append(TAG_METHOD_END);
requestBuilder.append(TAG_PARAMS_START);
for(Entry<String, String> param :paramsMap.entrySet()){
requestBuilder.append(TAG_PARAM_NAME_START);
requestBuilder.append(param.getKey());
requestBuilder.append(TAG_PARAM_NAME_END);
requestBuilder.append(TAG_PARAM_VALUE_START);
requestBuilder.append(param.getValue());
requestBuilder.append(TAG_PARAM_VALUE_END);
}
requestBuilder.append(TAG_SOAP_REQ_END);
return requestBuilder.toString();
}
/**
* Connection timeout set for the HttpClient
*/
private static final int CONNECTION_TIMEOUT= 6000;
/**
* Socket timeout set for the HttpClient
*/
private static final int SOCKET_TIMEOUT = 10000;
/**
* @return httpClient An instance of {@link DefaultHttpClient}
*/
private static DefaultHttpClient getHttpClient() {
HttpParams httpParameters = new BasicHttpParams();
// Set the timeout in milliseconds until a connection is established.
// The default value is zero, that means the timeout is not used.
HttpConnectionParams.setConnectionTimeout(httpParameters,CONNECTION_TIMEOUT);
// Set the default socket timeout (SO_TIMEOUT)
// in milliseconds which is the timeout for waiting for data.
HttpConnectionParams.setSoTimeout(httpParameters, SOCKET_TIMEOUT);
return new DefaultHttpClient(httpParameters);
}
/**
* Sends a SOAP request to the specified service endpoint.
*
* @param serviceEndpoint The service endpoint which will be hit
* @param soapRequest The SOAP request
* @return The string representing the response for the specified SOAP request.
*/
public static String send(String serviceEndpoint, String soapRequest){
HttpPost httppost = new HttpPost(serviceEndpoint);
StringEntity se = null;
try {
se = new StringEntity(soapRequest,HTTP.UTF_8);
} catch (UnsupportedEncodingException e) {
Log.e(TAG,"send", e);
return null;
}
se.setContentType("text/xml");
httppost.setHeader("Content-Type","application/soap+xml;charset=UTF-8");
httppost.setEntity(se);
String result = null;
HttpClient httpclient = getHttpClient();
try {
HttpResponse httpResponse = httpclient.execute(httppost);
HttpEntity responseEntity = httpResponse.getEntity();
if(null!= responseEntity){
//if you have a huge chunk of data read it using a buffer
result =EntityUtils.toString(responseEntity);
}
} catch (ClientProtocolException e) {
Log.e(TAG,"send", e);
} catch (IOException e) {
Log.e(TAG,"send", e);
} catch (Exception e){
Log.e(TAG,"send", e);
}
return result;
}
}
答案 1 :(得分:1)
我认为你需要另一种方法来创建标题,它看起来像jax-ws,所以我将使用几个月前做过的jax ws实现。
首先你需要一个HeaderHandler类,它创建了soap header元素,它应该是这样的:
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPHeader;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
public class HeaderHandler implements SOAPHandler<SOAPMessageContext> {
public boolean handleMessage(SOAPMessageContext smc) {
Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
String AUTH_TK = "http://www.avectra.com/2005/";
String PREFIX="";//no prefix
String PREFIX_XMLNS="xmlns";
String value = "123456";
if (outboundProperty.booleanValue()) {
try {
SOAPEnvelope envelope = smc.getMessage().getSOAPPart().getEnvelope();
SOAPHeader header = envelope.addHeader();
//<AuthorizationToken xmlns="http://www.avectra.com/2005/">
SOAPElement authorizationToken = header.addChildElement("AuthorizationToken", PREFIX_XMLNS, AUTH_TK);
//<Token>value</Token>
SOAPElement usernameToken =
authorizationToken.addChildElement("Token", PREFIX);
usernameToken.addTextNode(value);
} catch (Exception e) {
e.printStackTrace();
}
}
return outboundProperty;
}
public Set<QName> getHeaders() {
return null;
}
public void close(MessageContext arg0) {
}
public boolean handleFault(SOAPMessageContext arg0) {
return false;
}
}
之后,您创建一个HeaderHandlerResolver来处理标头创建并将其插入处理程序链中:
import java.util.ArrayList;
import java.util.List;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.HandlerResolver;
import javax.xml.ws.handler.PortInfo;
public class HeaderHandlerResolver implements HandlerResolver {
@SuppressWarnings("unchecked")
public List<Handler> getHandlerChain(PortInfo portInfo) {
List<Handler> handlerChain = new ArrayList<Handler>();
HeaderHandler hh = new HeaderHandler();
handlerChain.add(hh);
return handlerChain;
}
}
之后,您在客户端中添加:
try{
//new service instance (your service should be extending javax.xml.ws.Service;)
YourServiceProxy service = new YourServiceProxy();
//calls the header handler resolver ;)
service.setHandlerResolver(new HeaderHandlerResolver());
//get the service
YourService port = (YourService)service.getYourService();
//call the service
port.yourMethod()
} catch (Exception e) {
e.printStackTrace();
}
顺便说一句,我没有测试过这个特殊的标题,我修改过我之前的标题处理程序,所以它可能不准确,但我认为它非常接近,我真的希望它可以帮到你,试一试告诉我们它是怎么来的,如果它仍然不起作用,我会尽力帮助你。
答案 2 :(得分:0)
您是否检查过kSOAP为parameters
(即i:type="n1:parameters"
)和Parameter
(即i:type="n1:Parameter"
)节点生成的类型是否正确(它们是在wsdl中定义的) )?
尝试设置
envelope.implicitTypes = true;
还可以玩
envelope.setAddAdornments(false);
强制kSOAP不包含type属性和名称空格。