可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I\'m approaching iOS development and I\'d like to have one of my first applications to perform a HTTP POST request.
As far as I can understand, I should manage the connection which handles the request via a NSURLConnection
object, which forces me to have a delegate object, which in turn will handle data events.
Could someone please clarify the task with a practical example?
I should contact an https endpoint sending authentication data (username and password) and getting back a plain text response.
回答1:
You can use NSURLConnection as follows:
Set your NSURLRequest
: Use requestWithURL:(NSURL *)theURL
to initialise the request.
If you need to specify a POST request and/or HTTP headers, use NSMutableURLRequest
with
(void)setHTTPMethod:(NSString *)method
(void)setHTTPBody:(NSData *)data
(void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field
Send your request in 2 ways using NSURLConnection
:
Synchronously: (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error
This returns a NSData
variable that you can process.
IMPORTANT: Remember to kick off the synchronous request in a separate thread to avoid blocking the UI.
Asynchronously: (void)start
Don\'t forget to set your NSURLConnection\'s delegate to handle the connection as follows:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[self.data setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)d {
[self.data appendData:d];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@\"Error\", @\"\")
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:NSLocalizedString(@\"OK\", @\"\")
otherButtonTitles:nil] autorelease] show];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseText = [[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding];
// Do anything you want with it
[responseText release];
}
// Handle basic authentication challenge if needed
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
NSString *username = @\"username\";
NSString *password = @\"password\";
NSURLCredential *credential = [NSURLCredential credentialWithUser:username
password:password
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}
回答2:
EDIT: ASIHTTPRequest has been abandoned by the developer. It\'s still really good IMO, but you should probably look elsewhere now.
I\'d highly recommend using the ASIHTTPRequest library if you are handling HTTPS. Even without https it provides a really nice wrapper for stuff like this and whilst it\'s not hard to do yourself over plain http, I just think the library is nice and a great way to get started.
The HTTPS complications are far from trivial in various scenarios, and if you want to be robust in handling all the variations, you\'ll find the ASI library a real help.
回答3:
I thought I would update this post a bit and say that alot of the iOS community has moved over to AFNetworking after ASIHTTPRequest
was abandoned. I highly recommend it. It\'s a great wrapper around NSURLConnection
and allows for asynchronous calls, and basically anything you might need.
回答4:
Here is an updated answer for iOS7+. It uses NSURLSession, the new hotness. Disclaimer, this is untested and was written in a text field:
- (void)post {
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@\"https://example.com/dontposthere\"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
// Uncomment the following two lines if you\'re using JSON like I imagine many people are (the person who is asking specified plain text)
// [request addValue:@\"application/json\" forHTTPHeaderField:@\"Content-Type\"];
// [request addValue:@\"application/json\" forHTTPHeaderField:@\"Accept\"];
[request setHTTPMethod:@\"POST\"];
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}];
[postDataTask resume];
}
-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)( NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
}
Or better yet, use AFNetworking 2.0+. Usually I would subclass AFHTTPSessionManager, but I\'m putting this all in one method to have a concise example.
- (void)post {
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@\"https://example.com\"]];
// Many people will probably want [AFJSONRequestSerializer serializer];
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
// Many people will probably want [AFJSONResponseSerializer serializer];
manager.responseSerializer = [AFHTTPRequestSerializer serializer];
manager.securityPolicy.allowInvalidCertificates = NO; // Some servers require this to be YES, but default is NO.
[manager.requestSerializer setAuthorizationHeaderFieldWithUsername:@\"username\" password:@\"password\"];
[[manager POST:@\"dontposthere\" parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
NSString *responseString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@\"darn it\");
}] resume];
}
If you are using the JSON response serializer, the responseObject will be object from the JSON response (often NSDictionary or NSArray).
回答5:
NOTE: Pure Swift 3 (Xcode 8) example:
Please try out the following sample code. It is the simple example of dataTask
function of URLSession
.
func simpleDataRequest() {
//Get the url from url string
let url:URL = URL(string: \"YOUR URL STRING\")!
//Get the session instance
let session = URLSession.shared
//Create Mutable url request
var request = URLRequest(url: url as URL)
//Set the http method type
request.httpMethod = \"POST\"
//Set the cache policy
request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringCacheData
//Post parameter
let paramString = \"key=value\"
//Set the post param as the request body
request.httpBody = paramString.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest) {
(data, response, error) in
guard let _:Data = data as Data?, let _:URLResponse = response , error == nil else {
//Oops! Error occured.
print(\"error\")
return
}
//Get the raw response string
let dataString = String(data: data!, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))
//Print the response
print(dataString!)
}
//resume the task
task.resume()
}
回答6:
Xcode 8 and Swift 3.0
Using URLSession:
let url = URL(string:\"Download URL\")!
let req = NSMutableURLRequest(url:url)
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
let task : URLSessionDownloadTask = session.downloadTask(with: req as URLRequest)
task.resume()
URLSession Delegate call:
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask,
didWriteData bytesWritten: Int64, totalBytesWritten writ: Int64, totalBytesExpectedToWrite exp: Int64) {
print(\"downloaded \\(100*writ/exp)\" as AnyObject)
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL){
}
Using Block GET/POST/PUT/DELETE:
let request = NSMutableURLRequest(url: URL(string: \"Your API URL here\" ,param: param))!,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval:\"Your request timeout time in Seconds\")
request.httpMethod = \"GET\"
request.allHTTPHeaderFields = headers as? [String : String]
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest) {data,response,error in
let httpResponse = response as? HTTPURLResponse
if (error != nil) {
print(error)
} else {
print(httpResponse)
}
DispatchQueue.main.async {
//Update your UI here
}
}
dataTask.resume()
Working fine for me.. try it 100% result guarantee
回答7:
Here is how POST HTTP request works for iOS 8+ using NSURLSession:
- (void)call_PostNetworkingAPI:(NSURL *)url withCompletionBlock:(void(^)(id object,NSError *error,NSURLResponse *response))completion
{
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
config.URLCache = nil;
config.timeoutIntervalForRequest = 5.0f;
config.timeoutIntervalForResource =10.0f;
NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:nil delegateQueue:nil];
NSMutableURLRequest *Req=[NSMutableURLRequest requestWithURL:url];
[Req setHTTPMethod:@\"POST\"];
NSURLSessionDataTask *task = [session dataTaskWithRequest:Req completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error == nil) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
if (dict != nil) {
completion(dict,error,response);
}
}else
{
completion(nil,error,response);
}
}];
[task resume];
}
Hope this will satisfy your following requirement.