關(guān)于webservice
必須承認(rèn)杆怕,在移動端做webservice請求是一件很痛苦的事情——復(fù)雜的請求體拼接,緩慢的xml格式解析壳贪。
但是陵珍,在實(shí)際工作中,還是不可避免的遇到一些這樣的情況违施,那么互纯,讓我們盡量的做到代碼優(yōu)雅吧,不要讓soap請求打亂了本來的節(jié)奏磕蒲。
基于熟悉和優(yōu)雅的訴求留潦,webservice請求,我們還是基于的AFNetwork去做辣往。
核心問題在于:AFNetwork2.0中的AFHTTPRequestOperation已被廢棄兔院,如何使用AFHTTPSessionManager去修改HTTPBody。
好了站削,下面讓我們一起看一下
什么是soap
求助baidu(要是懶得看坊萝,跳過這一大段):
簡單對象訪問協(xié)議是交換數(shù)據(jù)的一種協(xié)議規(guī)范,是一種輕量的许起、簡單的十偶、基于XML(標(biāo)準(zhǔn)通用標(biāo)記語言下的一個子集)的協(xié)議,它被設(shè)計成在WEB上交換結(jié)構(gòu)化的和固化的信息园细。
基于類對象的傳輸協(xié)議惦积。
SOAP封裝(envelop),它定義了一個框架猛频,描述消息中的內(nèi)容是什么狮崩,是誰發(fā)送的,誰應(yīng)當(dāng)接受并處理它以及如何處理它們伦乔;
SOAP編碼規(guī)則(encoding rules),它定義了一種序列化機(jī)制董习,用于表示應(yīng)用程序需要使用的數(shù)據(jù)類型的實(shí)例烈和;
SOAP RPC表示(RPC representation),它定了一個協(xié)定皿淋,用于表示遠(yuǎn)程過程調(diào)用和應(yīng)答招刹;
SOAP綁定(binding)恬试,它定義了SOAP使用哪種協(xié)議交換信息。使用HTTP/TCP/UDP協(xié)議都可以疯暑。
把SOAP綁定到HTTP提供了同時利用SOAP的樣式和分散的靈活性的特點(diǎn)以及HTTP的豐富的特征庫的優(yōu)點(diǎn)训柴。在HTTP上傳送SOAP并不是說SOAP會覆蓋現(xiàn)有的HTTP語義,而是HTTP上的SOAP語義會自然的映射到HTTP語義妇拯。在使用HTTP作為協(xié)議綁定的場合中幻馁,RPC請求映射到HTTP請求上,而RPC應(yīng)答映射到HTTP應(yīng)答越锈。然而仗嗦,在RPC上使用SOAP并不僅限于HTTP協(xié)議綁定。
——————自己理解————————:
這是一種webservice協(xié)議甘凭,本質(zhì)來說稀拐,還是HTTP請求唄,還是那個老樣子丹弱,分為HTTPHeader和HTTPBody
AFNetwork封裝的很好德撬,所以很多人可能已經(jīng)不了解底層,AFNetwork以及蘋果的請求體只讓你看到配置部分躲胳,不給你看到xml格式的請求體蜓洪。但是現(xiàn)在,soap請求泛鸟,請你自己拼HTTPBody蝠咆。
先去下載一個soapUI,這是一個非常強(qiáng)大的工具北滥。把服務(wù)端給你的那個以?wdsl結(jié)尾的地址刚操,放進(jìn)去,可以讀出所有的方法再芋,以及你要去拼寫的那個soap envelop(也就是信封)格式菊霜。點(diǎn)擊運(yùn)行,當(dāng)然济赎,你也可以查看運(yùn)行結(jié)果鉴逞。
soapui下載地址 http://www.soapui.org/
如果你必須要做soap接口請求了,務(wù)必下載K狙怠9辜瘛!
1.關(guān)于NSMutableURLRequest
相信很多AFNetwork2.0訪問webservice的例子中壳猜,都構(gòu)建了NSMutableURLRequest勾徽,不贅述了,上代碼
- (NSMutableURLRequest *)loadRequestWithParameter:(NSString *)parameter url:(NSString *)urlString methodName:(NSString *)methodName{
NSString *soapMessage =
[NSString stringWithFormat:
@"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:agen=\"http://agent.water.tjswfxkh/\" >"
"<soapenv:Body>"
"<agen:%@>"
"<arg0>%@</arg0>"
"</agen:%@>"
"</soapenv:Body>"
"</soapenv:Envelope>", methodName,parameter,methodName
];
// 將這個XML字符串打印出來
NSLog(@"%@", soapMessage);
// 創(chuàng)建URL统扳,內(nèi)容是前面的請求報文報文中第二行主機(jī)地址加上第一行URL字段
NSURL *url = [NSURL URLWithString:urlString];
// 根據(jù)上面的URL創(chuàng)建一個請求
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
NSString *msgLengt = [NSString stringWithFormat:@"%ld", [soapMessage length]];
// 添加請求的詳細(xì)信息喘帚,與請求報文前半部分的各字段對應(yīng)
[req addValue:@"application/soap+xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
[req addValue:msgLengt forHTTPHeaderField:@"Content-Length"];
// 設(shè)置請求行方法為POST畅姊,與請求報文第一行對應(yīng)
[req setHTTPMethod:@"POST"];
// 將SOAP消息加到請求中
[req setHTTPBody: [soapMessage dataUsingEncoding:NSUTF8StringEncoding]];
return req;
}
代碼潔癖,封裝了一個方法做這個事情吹由。入?yún)⒎謩e是參數(shù)若未、地址、soap方法名倾鲫。這樣我們就可以復(fù)用了粗合,對不對。畢竟在同一個項(xiàng)目中级乍,xml標(biāo)簽?zāi)遣糠稚嗬停皇悄敲慈菀赘淖儭?/p>
soapMessage的來源,就是soapUI中玫荣,說過的信封請求體甚淡,你只要保證和它拼的一樣就ok,setHTTPBody會將這部分捅厂,加到request里贯卦。
2.AFHTTPSessionManager
進(jìn)行到這一步,那么焙贷,怎么把request加載到SessionManager呢
在AFNetwork2.0中關(guān)于AFHTTPRequestOperation撵割,是這樣子的
NSString *parameter = @"{\"endDate\":\"2015-06-01 08\",\"beginDate\":\"2015-06-01 08\"}";
NSString *urlStr = @"http://10.3.211.111/hw/cxf/water";
NSString *methodName = @"getSqInfo";
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:[self loadRequestWithParameter:parameter url:urlStr methodName:methodName]];
operation.responseSerializer = [AFXMLParserResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
//parse NSXMLParser object here if request successfull
if ([responseObject isKindOfClass:[NSXMLParser class]]) {
NSXMLParser *parser = (NSXMLParser *)responseObject;
NSError *parseError = nil;
NSDictionary *dict = [XMLReader dictionaryForNSXMLParser:parser error:&parseError];
NSLog(@"JSON: %@ - %@", responseObject,dict);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
[[NSOperationQueue mainQueue] addOperation:operation];
AFHTTPRequestOperation被廢棄后,AFNetwork3.0結(jié)合AFHTTPSessionManager
精華的部分來了U奚帧7缺颉!故硅!
NSString *parameter = @"{\"endDate\":\"2015-06-01 08\",\"beginDate\":\"2015-06-01 08\"}";
NSString *urlStr = @"http://10.3.211.111/hw/cxf/water";
NSString *methodName = @"getSqInfo";
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
//回復(fù)的序列化
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[[manager dataTaskWithRequest:[self loadRequestWithParameter:parameter url:urlStr methodName:methodName] completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
if (!error) {
NSData * data = (NSData *)responseObject;
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
NSError *parseError = nil;
NSDictionary *dict = [XMLReader dictionaryForNSXMLParser:parser error:&parseError];
NSLog(@"JSON: %@ - %@", responseObject,dict);
} else {
NSLog(@"Error: %@, %@, %@", error, response, responseObject);
}
}] resume];
務(wù)必要加這句話庶灿,不然在返回xml格式response時候,會報錯吃衅,進(jìn)到error狀態(tài)往踢,但實(shí)際上HTTP請求state code=200,即請求已經(jīng)成功徘层。
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
3.xml解析
上述代碼經(jīng)過本地服務(wù)的測試峻呕,已經(jīng)跑通,不出意外的話趣效,你會拿到一個NSData瘦癌,解析后,是一個xml格式數(shù)據(jù)跷敬。
在這里用到了XMLReader讯私,將其轉(zhuǎn)換成了一個字典。
4.代碼下載
演示代碼已經(jīng)上傳,歡迎下載妄帘,希望能對大家有些幫助
https://github.com/Rita5969/afnetwork3.0-for-webservice
5.參考
非常非常感謝Pranoy C在stackoverflow貢獻(xiàn)的答案
http://stackoverflow.com/questions/34561215/afnetworking-3-0-migration-how-to-post-with-headers-and-http-body
XMLReader-xml解析器
https://github.com/amarcadet/XMLReader
AFNetwork3.0遷移指南-官方Readme的中文翻譯
http://www.reibang.com/p/047463a7ce9b
———————————————————————————————————————————————————————————————————
如果大家對示例中的寫法有好的建議,歡迎指正池凄。后期如果有更好的方案抡驼,會繼續(xù)更新。謝謝肿仑。