转自 http://www.cocoachina.com/bbs/read.php?tid=98388
工作中,使用iPhone作为已有产品的移动终端,目前做能想到最理想的方式就是恳求产品提供WebService了,还是老习惯,坚决不要零散的代码,继续整理为通用的类,便于拉壮丁快速开发,虽然目前的壮丁就俺一个,hoho
再次利用现有的资源,使用了ASIHttpRequest v1.8.1,因为项目中使用了Windows集成验证,而这个东西正好提供了响应的验证方式,爽歪歪了。
还是那句话:只是单纯的希望,大家都能有共享学习的精神!
再一个,项目都是.Net相关的,在浏览器中访问.Net WebService的asmx文件时,会返回一系列帮助文件,让我们了解这个WebService有几个调用方法,每个方法的入口参数是什么,返回值是什么,这次使用了SOAP1.1的规范。
再再一个,这个类并不完善,WebService某个方法的参数,必须是简单的数据类型,如数值、字符等等,不支持数据集等对象,等以后需要了再完善吧,呵呵。
再再再一个,调用后的响应解析,是另一个课题,不在这里讲啦,预报下,如果响应中包含了.Net的数据集,也是自己写了通用类可以解析滴,嘎嘎。
再再再再一个,保证是最后一个再了,代码里面看到这个 [Constant sharedConstant].P_SYSTEM_URL ,就去看看前一篇文章吧,单例模式实现常量存储,哈哈。
1、先看看调用说明:
自定义WebService访问类,需要使用下面这个字符串作为SOAP请求,通过POST的方式,提交给WebService
- POST /iwscooperationws/todocenter.asmx HTTP/1.1
- Host: 192.168.1.11
- Content-Type: text/xml; charset=utf-8
- Content-Length: length
- SOAPAction: "http://iws.CP.ws/GetWorkflowToDoCount"
- <?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:Body>
- <GetWorkflowToDoCount xmlns="http://iws.CP.ws/">
- <UserName>string</UserName>
- </GetWorkflowToDoCount>
- </soap:Body>
- </soap:Envelope>
2、.h文件中的声明,注释都放到了.m文件中,这是个人习惯:
- + (ASIHTTPRequest *)getASISOAP11Request:(NSString *) WebURL
- webServiceFile:(NSString *) wsFile
- xmlNameSpace:(NSString *) xmlNS
- webServiceName:(NSString *) wsName
- wsParameters:(NSMutableArray *) wsParas;
- + (NSString *)getSOAP11WebServiceResponse:(NSString *) WebURL
- webServiceFile:(NSString *) wsFile
- xmlNameSpace:(NSString *) xmlNS
- webServiceName:(NSString *) wsName
- wsParameters:(NSMutableArray *) wsParas;
- + (NSString *)getSOAP11WebServiceResponseWithNTLM:(NSString *) WebURL
- webServiceFile:(NSString *) wsFile
- xmlNameSpace:(NSString *) xmlNS
- webServiceName:(NSString *) wsName
- wsParameters:(NSMutableArray *) wsParas
- userName:(NSString *) userName
- passWord:(NSString *) passWord;
- + (NSString *)checkResponseError:(NSString *) theResponse;
3、.m文件的实现之一,生成ASIHttpRequest请求:
- /*
- //Mark: 生成SOAP1.1版本的ASIHttp请求
- 参数 webURL: 远程WebService的地址,不含*.asmx
- 参数 webServiceFile: 远程WebService的访问文件名,如service.asmx
- 参数 xmlNS: 远程WebService的命名空间
- 参数 webServiceName: 远程WebService的名称
- 参数 wsParameters: 调用参数数组,形式为[参数1名称,参数1值,参数2名称,参数2值⋯⋯],如果没有调用参数,此参数为nil
- */
- + (ASIHTTPRequest *)getASISOAP11Request:(NSString *) WebURL
- webServiceFile:(NSString *) wsFile
- xmlNameSpace:(NSString *) xmlNS
- webServiceName:(NSString *) wsName
- wsParameters:(NSMutableArray *) wsParas
- {
- //1、初始化SOAP消息体
- NSString * soapMsgBody1 = [[NSString alloc] initWithFormat:
- @"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
- "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n"
- "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" \n"
- "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
- "<soap:Body>\n"
- "<%@ xmlns=\"%@\">\n", wsName, xmlNS];
- NSString * soapMsgBody2 = [[NSString alloc] initWithFormat:
- @"</%@>\n"
- "</soap:Body>\n"
- "</soap:Envelope>", wsName];
- //2、生成SOAP调用参数
- NSString * soapParas = [[NSString alloc] init];
- soapParas = @"";
- if (![wsParas isEqual:nil]) {
- int i = 0;
- for (i = 0; i < [wsParas count]; i = i + 2) {
- soapParas = [soapParas stringByAppendingFormat:@"<%@>%@</%@>\n",
- [wsParas objectAtIndex:i],
- [wsParas objectAtIndex:i+1],
- [wsParas objectAtIndex:i]];
- }
- }
- //3、生成SOAP消息
- NSString * soapMsg = [soapMsgBody1 stringByAppendingFormat:@"%@%@", soapParas, soapMsgBody2];
- //请求发送到的路径
- NSURL * url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", WebURL, wsFile]];
- //NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
- ASIHTTPRequest * theRequest = [ASIHTTPRequest requestWithURL:url];
- NSString *msgLength = [NSString stringWithFormat:@"%d", [soapMsg length]];
- //以下对请求信息添加属性前四句是必有的,第五句是soap信息。
- [theRequest addRequestHeader:@"Content-Type" value:@"text/xml; charset=utf-8"];
- [theRequest addRequestHeader:@"SOAPAction" value:[NSString stringWithFormat:@"%@%@", xmlNS, wsName]];
- [theRequest addRequestHeader:@"Content-Length" value:msgLength];
- [theRequest setRequestMethod:@"POST"];
- [theRequest appendPostData:[soapMsg dataUsingEncoding:NSUTF8StringEncoding]];
- [theRequest setDefaultResponseEncoding:NSUTF8StringEncoding];
- return theRequest;
- }
4、.m文件的实现之二,同步调用WebService请求,返回响应字符串
- #pragma mark -
- /*
- //Mark: 使用SOAP1.1同步调用WebService请求
- 参数 webURL: 远程WebService的地址,不含*.asmx
- 参数 webServiceFile: 远程WebService的访问文件名,如service.asmx
- 参数 xmlNS: 远程WebService的命名空间
- 参数 webServiceName: 远程WebService的名称
- 参数 wsParameters: 调用参数数组,形式为[参数1名称,参数1值,参数2名称,参数2值⋯⋯],如果没有调用参数,此参数为nil
- */
- + (NSString *)getSOAP11WebServiceResponse:(NSString *) WebURL
- webServiceFile:(NSString *) wsFile
- xmlNameSpace:(NSString *) xmlNS
- webServiceName:(NSString *) wsName
- wsParameters:(NSMutableArray *) wsParas
- {
- //创建请求
- ASIHTTPRequest * theRequest = [self getASISOAP11Request:WebURL
- webServiceFile:wsFile
- xmlNameSpace:xmlNS
- webServiceName:wsName
- wsParameters:wsParas];
- //显示网络请求信息在status bar上
- [ASIHTTPRequest setShouldUpdateNetworkActivityIndicator:YES];
- //同步调用
- [theRequest startSynchronous];
- NSError *error = [theRequest error];
- if (!error) {
- return [theRequest responseString];
- }
- else {
- //出现调用错误,则使用错误前缀+错误描述
- return [NSString stringWithFormat:@"%@%@", [Constant sharedConstant].G_WEBSERVICE_ERROR, [error localizedDescription]];
- }
- }
5、.m文件实现之三,同步调用需要Windows集成验证的WebService请求,返回响应字符串:
- #pragma mark -
- /*
- //Mark: 使用SOAP1.1同步调用WebService请求,需提供Windows集成验证的用户名、密码和域
- 参数 webURL: 远程WebService的地址,不含*.asmx
- 参数 webServiceFile: 远程WebService的访问文件名,如service.asmx
- 参数 xmlNS: 远程WebService的命名空间
- 参数 webServiceName: 远程WebService的名称
- 参数 wsParameters: 调用参数数组,形式为[参数1名称,参数1值,参数2名称,参数2值⋯⋯],如果没有调用参数,此参数为nil
- 参数 userName 用户名--目前来看,不需要输入域信息
- 参数 passWord 密码
- */
- + (NSString *)getSOAP11WebServiceResponseWithNTLM:(NSString *) WebURL
- webServiceFile:(NSString *) wsFile
- xmlNameSpace:(NSString *) xmlNS
- webServiceName:(NSString *) wsName
- wsParameters:(NSMutableArray *) wsParas
- userName:(NSString *) userName
- passWord:(NSString *) passWord
- {
- //创建请求
- ASIHTTPRequest * theRequest = [self getASISOAP11Request:WebURL
- webServiceFile:wsFile
- xmlNameSpace:xmlNS
- webServiceName:wsName
- wsParameters:wsParas];
- //集成验证NTLM用户名,密码和域设置
- [theRequest setUsername:userName];
- [theRequest setPassword:passWord];
- //[theRequest setDomain:doMain];
- //显示网络请求信息在status bar上
- [ASIHTTPRequest setShouldUpdateNetworkActivityIndicator:YES];
- //同步调用
- [theRequest startSynchronous];
- NSError *error = [theRequest error];
- if (!error) {
- return [theRequest responseString];
- }
- else {
- //出现调用错误,则使用错误前缀+错误描述
- return [NSString stringWithFormat:@"%@%@", [Constant sharedConstant].G_WEBSERVICE_ERROR, [error localizedDescription]];
- }
- }
6、.m文件实现之四,响应字符串中是否包含错误信息,简单处理了下错误消息的中文显示:
- #pragma mark -
- /*
- //Mark: 检查WebService的Response是否包含错误信息
- 如果未包含错误,则返回零长度字符串
- 否则返回错误描述
- 错误信息格式:错误前缀\n错误描述
- */
- + (NSString *)checkResponseError:(NSString *) theResponse
- {
- //检查消息是否包含错误前缀
- if (![theResponse hasPrefix:[Constant sharedConstant].G_WEBSERVICE_ERROR]) {
- return @"";
- }
- else {
- NSMutableString *sTemp = [[NSMutableString alloc] initWithString:theResponse];
- //获取错误前缀的范围
- NSRange range=[sTemp rangeOfString:[Constant sharedConstant].G_WEBSERVICE_ERROR];
- //剔除错误前缀
- [sTemp replaceCharactersInRange:range withString:@""];
- NSString * errMsg = sTemp;
- //Authentication needed
- if ([sTemp isEqualToString:@"Authentication needed"]) {
- errMsg = @"用户登录失败!";
- }
- //The request timed out
- if ([sTemp isEqualToString:@"The request timed out"]) {
- errMsg = @"访问超时,请检查远程地址等基本设置!";
- }
- //The request was cancelled
- if ([sTemp isEqualToString:@"The request was cancelled"]) {
- errMsg = @"请求被撤销!";
- }
- //Unable to create request (bad url?)
- if ([sTemp isEqualToString:@"Unable to create request (bad url?)"]) {
- errMsg = @"无法创建请求,错误的URL地址!";
- }
- //The request failed because it redirected too many times
- if ([sTemp isEqualToString:@"The request failed because it redirected too many times"]) {
- errMsg = @"请求失败,可能是因为被重定向次数过多!";
- }
- //A connection failure occurred
- if ([sTemp isEqualToString:@"A connection failure occurred"]) {
- errMsg = @"网络连接错误,请检查无线或3G网络设置!";
- }
- return errMsg;
- }
- }
7、开始调用啦:
- //创建WebService的调用参数
- NSMutableArray * wsParas = [[NSMutableArray alloc] initWithObjects:
- @"UserName", [Constant sharedConstant].P_USER_NAME,
- nil nil];
- //调用WebService,获取响应
- NSString * theResponse = [WebService getSOAP11WebServiceResponseWithNTLM:[Constant sharedConstant].P_SYSTEM_URL
- webServiceFile:[Constant sharedConstant].G_WS_TODOCENTER
- xmlNameSpace:[Constant sharedConstant].G_WEBSERVICE_NAMESPACE
- webServiceName:[Constant sharedConstant].G_WS_TODOCENTER_GETWORKFLOWTODOCOUNT
- wsParameters:wsParas
- userName:[Constant sharedConstant].P_USER_NAME
- passWord:[Constant sharedConstant].P_PASSWORD];
- //检查响应中是否包含错误
- NSString * errMsg = [WebService checkResponseError:theResponse];
- //接下来的代码就是检查errMsg有没有内容
- //再接下来就是theResponse响应字符串的解析了