在 Android_WebServices_介绍一文中,简单介绍了WebServices的基础知识,下面主要分析 ksoap2-android-assembly-3.3.0-jar-with-dependencies.jar实现源码。
1.调用WebServices流程
public void getRemoteInfo(String phoneSec) {
String nameSpace = "http://WebXml.com.cn/";
String methodName = "getMobileCodeInfo";
String endPoint = "http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx";
String soapAction = "http://WebXml.com.cn/getMobileCodeInfo";
// 1.初始化 SoapObject对象,为该方法设置参数,相当于信体
SoapObject request = new SoapObject(nameSpace, methodName);
request.addProperty("mobileCode", phoneSec);
request.addProperty("userId", "");
// 2.实例化SoapSerializationEnvelope对象,相当于信皮
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER10);
envelope.bodyOut = request;
envelope.dotNet = true;//兼容.net开发的Net-Services
// 3.实例化HttpTransportSE对象,还可以指定放了访问的请求时间
HttpTransportSE transport = new HttpTransportSE(endPoint);
//HttpTransportSE transport = new HttpTransportSE(endPoint, timeout);
try {
// 4.核心方法调用,其中soapActon在SoapSerializationEnvelope.VER12时无效,且为POST请求
transport.call(soapAction, envelope);
SoapObject response = (SoapObject) envelope.bodyIn;
final String result = response.getProperty(0).toString();//Vector
toast(result);
} catch (Exception e) {
e.printStackTrace();
toast(e.getMessage());
}
}
2.transport.call关键源码分析
/**
* Perform a soap call with a given namespace and the given envelope providing
* any extra headers that the user requires such as cookies. Headers that are
* returned by the web service will be returned to the caller in the form of a
* <code>List</code> of <code>HeaderProperty</code> instances.
*
* @param soapAction
* the namespace with which to perform the call in.
* @param envelope
* the envelope the contains the information for the call.
* @param headers
* <code>List</code> of <code>HeaderProperty</code> headers to send with the SOAP request.
* @param outputFile
* a file to stream the response into rather than parsing it, streaming happens when file is not null
*
* @return Headers returned by the web service as a <code>List</code> of
* <code>HeaderProperty</code> instances.
*
* @throws HttpResponseException
* an IOException when Http response code is different from 200
*/
public List call(String soapAction, SoapEnvelope envelope, List headers, File outputFile)
throws HttpResponseException, IOException, XmlPullParserException {
if (soapAction == null) {
soapAction = "\"\"";
}
//根据envelope,将其序列化为一个请求字节数组
byte[] requestData = createRequestData(envelope, "UTF-8");
// debug=true, requestDump的值为请求的数据,方便调试
requestDump = debug ? new String(requestData) : null;
responseDump = null;
//connection = new ServiceConnectionSE(proxy, url, timeout);包括设置时间
ServiceConnection connection = getServiceConnection();
connection.setRequestProperty("User-Agent", USER_AGENT);
// SOAPAction is not a valid header for VER12 so do not add
// it
// @see "http://code.google.com/p/ksoap2-android/issues/detail?id=67
if (envelope.version != SoapSerializationEnvelope.VER12) {
connection.setRequestProperty("SOAPAction", soapAction);
}
if (envelope.version == SoapSerializationEnvelope.VER12) {
connection.setRequestProperty("Content-Type", CONTENT_TYPE_SOAP_XML_CHARSET_UTF_8);
} else {
connection.setRequestProperty("Content-Type", CONTENT_TYPE_XML_CHARSET_UTF_8);
}
// this seems to cause issues so we are removing it
//connection.setRequestProperty("Connection", "close");
connection.setRequestProperty("Accept-Encoding", "gzip");
// Pass the headers provided by the user along with the call
if (headers != null) {
for (int i = 0; i < headers.size(); i++) {
HeaderProperty hp = (HeaderProperty) headers.get(i);
connection.setRequestProperty(hp.getKey(), hp.getValue());
}
}
// POST请求
connection.setRequestMethod("POST");
//发送数据,耗时较长,将requestData发送至connection的输出流
sendData(requestData, connection, envelope);
requestData = null;
InputStream is = null;
List retHeaders = null;
byte[] buf = null; // To allow releasing the resource after used
int contentLength = 8192; // To determine the size of the response and adjust buffer size
boolean gZippedContent = false;
boolean xmlContent = false;
// 得到响应码
int status = connection.getResponseCode();
try {
//得到响应头
retHeaders = connection.getResponseProperties();
for (int i = 0; i < retHeaders.size(); i++) {
HeaderProperty hp = (HeaderProperty)retHeaders.get(i);
// HTTP response code has null key
if (null == hp.getKey()) {
continue;
}
// If we know the size of the response, we should use the size to initiate vars
if (hp.getKey().equalsIgnoreCase("content-length") ) {
if ( hp.getValue() != null ) {
try {
contentLength = Integer.parseInt( hp.getValue() );
} catch ( NumberFormatException nfe ) {
contentLength = 8192;
}
}
}
// Check the content-type header to see if we're getting back XML, in case of a
// SOAP fault on 500 codes
if (hp.getKey().equalsIgnoreCase("Content-Type")
&& hp.getValue().contains("xml")) {
xmlContent = true;
}
// ignoring case since users found that all smaller case is used on some server
// and even if it is wrong according to spec, we rather have it work..
if (hp.getKey().equalsIgnoreCase("Content-Encoding")
&& hp.getValue().equalsIgnoreCase("gzip")) {
gZippedContent = true;
}
}
//first check the response code....
if (status != 200) {
//throw new IOException("HTTP request failed, HTTP status: " + status);
throw new HttpResponseException("HTTP request failed, HTTP status: " + status, status);
}
if (contentLength > 0) {
if (gZippedContent) {
is = getUnZippedInputStream(
new BufferedInputStream(connection.openInputStream(),contentLength));
} else {
is = new BufferedInputStream(connection.openInputStream(),contentLength);
}
}
} catch (IOException e) {
if (contentLength > 0) {
if(gZippedContent) {
is = getUnZippedInputStream(
new BufferedInputStream(connection.getErrorStream(),contentLength));
} else {
is = new BufferedInputStream(connection.getErrorStream(),contentLength);
}
}
if ( e instanceof HttpResponseException) {
if (!xmlContent) {
if (debug && is != null) {
//go ahead and read the error stream into the debug buffers/file if needed.
readDebug(is, contentLength, outputFile);
}
//we never want to drop through to attempting to parse the HTTP error stream as a SOAP response.
connection.disconnect();
throw e;
}
}
}
// debug=true responseDump=响应数据,方便调试
if (debug) {
is = readDebug(is, contentLength, outputFile);
}
// 根据is流,将流数据解析至 envelope.bodyIn中去
parseResponse(envelope, is,retHeaders);
//释放资源
is = null;
buf = null;
connection.disconnect();
connection = null;
// 返回响应头
return retHeaders;
}
Android_WebServices_源码分析