NSURLRequest : 发布数据并读取发布的页面
Posted
技术标签:
【中文标题】NSURLRequest : 发布数据并读取发布的页面【英文标题】:NSURLRequest : Post data and read the posted page 【发布时间】:2012-04-24 14:46:38 【问题描述】:在 ios(当前目标 5.0,Base SDK 5.1)中,如何向服务器发送发布请求,然后读取页面内容。例如,页面采用用户名和密码,然后回显 true 或 false。这只是为了更好地理解 NSURLRequest。
提前致谢!
【问题讨论】:
这是一个常见的问题,你尝试用谷歌搜索吗? @Niko 如果 SO 还没有问题,在这里发布问题不是问题。我用谷歌搜索,谷歌把我发到这里。 【参考方案1】:先做几件事
决定如何对数据进行编码 - JSON 或 url 编码是一个好的开始。 确定返回值 - 它是 1、TRUE 还是 0、FALSE,甚至是 YES/非零空/零。 阅读URL Loading System,这是你的朋友。旨在使您的所有 url 连接异步,以便您的 UI 保持响应。您可以使用 NSURLConnectionDelegate 回调来做到这一点。 NSURLConnection 有个小缺点:你的代码必须解耦。您希望在委托函数中可用的任何变量都需要保存到 ivars 或您请求的 userInfo 字典中。
您也可以使用 GCD,它与 __block 限定符结合使用时,允许您在声明它的位置指定错误/返回代码 - 对于一次性提取很有用。
事不宜迟,这是一个快速而肮脏的 url-encoder:
- (NSData*)encodeDictionary:(NSDictionary*)dictionary
NSMutableArray *parts = [[NSMutableArray alloc] init];
for (NSString *key in dictionary)
NSString *encodedValue = [[dictionary objectForKey:key] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *encodedKey = [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *part = [NSString stringWithFormat: @"%@=%@", encodedKey, encodedValue];
[parts addObject:part];
NSString *encodedDictionary = [parts componentsJoinedByString:@"&"];
return [encodedDictionary dataUsingEncoding:NSUTF8StringEncoding];
使用像 JSONKit 这样的 JSON 库可以让编码变得更容易,考虑一下!
方法 1 - NSURLConnectionDelegate 异步回调:
// .h
@interface ViewController : UIViewController<NSURLConnectionDelegate>
@end
// .m
@interface ViewController ()
NSMutableData *receivedData_;
@end
...
- (IBAction)asyncButtonPushed:(id)sender
NSURL *url = [NSURL URLWithString:@"http://localhost/"];
NSDictionary *postDict = [NSDictionary dictionaryWithObjectsAndKeys:@"user", @"username",
@"password", @"password", nil];
NSData *postData = [self encodeDictionary:postDict];
// Create the request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"POST"];
[request setValue:[NSString stringWithFormat:@"%d", postData.length] forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded charset=utf-8" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:postData];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
[connection start];
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
[receivedData_ setLength:0];
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
[receivedData_ appendData:data];
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
NSLog(@"Succeeded! Received %d bytes of data", [receivedData_ length]);
NSString *responeString = [[NSString alloc] initWithData:receivedData_
encoding:NSUTF8StringEncoding];
// Assume lowercase
if ([responeString isEqualToString:@"true"])
// Deal with true
return;
// Deal with an error
方法 2 - Grand Central Dispatch 异步函数:
// .m
- (IBAction)dispatchButtonPushed:(id)sender
NSURL *url = [NSURL URLWithString:@"http://www.apple.com/"];
NSDictionary *postDict = [NSDictionary dictionaryWithObjectsAndKeys:@"user", @"username",
@"password", @"password", nil];
NSData *postData = [self encodeDictionary:postDict];
// Create the request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"POST"];
[request setValue:[NSString stringWithFormat:@"%d", postData.length] forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded charset=utf-8" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:postData];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
// Peform the request
NSURLResponse *response;
NSError *error = nil;
NSData *receivedData = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if (error)
// Deal with your error
if ([response isKindOfClass:[NSHTTPURLResponse class]])
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
NSLog(@"HTTP Error: %d %@", httpResponse.statusCode, error);
return;
NSLog(@"Error %@", error);
return;
NSString *responeString = [[NSString alloc] initWithData:receivedData
encoding:NSUTF8StringEncoding];
// Assume lowercase
if ([responeString isEqualToString:@"true"])
// Deal with true
return;
// Deal with an error
// When dealing with UI updates, they must be run on the main queue, ie:
// dispatch_async(dispatch_get_main_queue(), ^(void)
//
// );
);
方法 3 - 使用 NSURLConnection 便利函数
+ (void)sendAsynchronousRequest:(NSURLRequest *)request queue:(NSOperationQueue *)queue completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler
希望这会有所帮助。
【讨论】:
@Matt 如果我想从 Web 服务进行 2 次提取,一个用于 usersArray,另一个用于 userPoints 数组并使用它们填充详细信息类型 uitableviewcell,哪个选项最好? @Matt,请看这篇文章:***.com/questions/17415191/… @Matt 为什么我们要将 sendSynchronous NSURLConnection 调用分派到主队列?我们不是在主队列上并且应该将它分派到另一个队列吗?我很困惑:s 错误。更新了答案以反映这一点。 如果您收到 406 HTTP 错误状态代码,请从 [request setValue:@"application/x-www-form-urlencoded charset=utf-8" forHTTPHeaderField 中删除“charset=utf-8”: @"Content-Type"];【参考方案2】: NSData *postData = [someStringToPost dataUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:someURLString];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
[req setHTTPMethod:@"POST"];
[req setValue:[NSString stringWithFormat:@"%d", postData.length] forHTTPHeaderField:@"Content-Length"];
[req setValue:@"application/x-www-form-urlencoded charset=utf-8" forHTTPHeaderField:@"Content-Type"];
[req setHTTPBody:postData];
NSError *err = nil;
NSHTTPURLResponse *res = nil;
NSData *retData = [NSURLConnection sendSynchronousRequest:req returningResponse:&res error:&err];
if (err)
//handle error
else
//handle response and returning data
【讨论】:
@Lefteris 异步请求以类似方式完成,代理 404 应该通过谷歌搜索找出方法。我认为问题主要是关于发布数据,并且在异步请求中不会改变。但是,我认为很多时候没有必要触发异步,那么为什么推荐使用它总是? 因为同步阻塞了主线程,也就是用户界面,用户可能想知道发生了什么...... @Lefteris 实际上,说它阻塞了主线程并不完全正确。它只会阻塞它正在运行的线程,所以如果该线程是后台线程,那么它不会阻塞主线程。 @bugfixr 正确,但这是最常见的情况【参考方案3】:这个项目可能对您的目的非常方便。它将处理您的下载并将其存储在本地。查看链接https://github.com/amitgowda/AGInternetHandler
【讨论】:
这并不能真正回答问题。 即使没有正确实施。 @DonCruickshank以上是关于NSURLRequest : 发布数据并读取发布的页面的主要内容,如果未能解决你的问题,请参考以下文章
是否可以防止 NSURLRequest 在请求后缓存数据或删除缓存的数据?
从 NSURLRequest 以编程方式按下 html 按钮
如何将 NSURLRequest 的结果传递回包含类 [重复]
在 ObjC 中使用 NSURLRequest 在 URL 中发送 SQL 查询
IOS NSURLRequest下Webview Ajax应用超时设置
NSURLRequest 返回 NSURLErrorNetworkConnectionLost 但可达性表明网络连接已开启