在 iOS 上发送 HTTP POST 请求
Posted
技术标签:
【中文标题】在 iOS 上发送 HTTP POST 请求【英文标题】:Sending an HTTP POST request on iOS 【发布时间】:2013-04-01 18:42:07 【问题描述】:我正在尝试使用我正在开发的 ios 应用程序发送 HTTP Post,但推送从未到达服务器,尽管我确实收到了代码 200 作为响应(来自 urlconnection)。我从来没有得到服务器的响应,服务器也没有检测到我的帖子(服务器确实检测到来自 android 的帖子)
我确实使用 ARC,但已将 pd 和 urlConnection 设置为强。
这是我发送请求的代码
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@%@",dk.baseURL,@"daantest"]]];
[request setHTTPMethod:@"POST"];
[request setValue:@"text/xml"
forHTTPHeaderField:@"Content-type"];
NSString *sendString = @"<data><item>Item 1</item><item>Item 2</item></data>";
[request setValue:[NSString stringWithFormat:@"%d", [sendString length]] forHTTPHeaderField:@"Content-length"];
[request setHTTPBody:[sendString dataUsingEncoding:NSUTF8StringEncoding]];
PushDelegate *pushd = [[PushDelegate alloc] init];
pd = pushd;
urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:pd];
[urlConnection start];
这是我的委托代码
#import "PushDelegate.h"
@implementation PushDelegate
@synthesize data;
-(id) init
if(self = [super init])
data = [[NSMutableData alloc]init];
[data setLength:0];
return self;
- (void)connection:(NSURLConnection *)connection didWriteData:(long long)bytesWritten totalBytesWritten:(long long)totalBytesWritten
NSLog(@"didwriteData push");
- (void)connectionDidResumeDownloading:(NSURLConnection *)connection totalBytesWritten:(long long)totalBytesWritten expectedTotalBytes:(long long)expectedTotalBytes
NSLog(@"connectionDidResumeDownloading push");
- (void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL
NSLog(@"didfinish push @push %@",data);
- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite
NSLog(@"did send body");
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
[self.data setLength:0];
NSHTTPURLResponse *resp= (NSHTTPURLResponse *) response;
NSLog(@"got response with status @push %d",[resp statusCode]);
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)d
[self.data appendData:d];
NSLog(@"recieved data @push %@", data);
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
NSString *responseText = [[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding];
NSLog(@"didfinishLoading%@",responseText);
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error ", @"")
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:NSLocalizedString(@"OK", @"")
otherButtonTitles:nil] show];
NSLog(@"failed &push");
// Handle basic authentication challenge if needed
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
NSLog(@"credentials requested");
NSString *username = @"username";
NSString *password = @"password";
NSURLCredential *credential = [NSURLCredential credentialWithUser:username
password:password
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
@end
控制台总是打印以下行并且只打印以下行:
2013-04-01 20:35:04.341 ApprenticeXM[3423:907] did send body
2013-04-01 20:35:04.481 ApprenticeXM[3423:907] got response with status @push 200
2013-04-01 20:35:04.484 ApprenticeXM[3423:907] didfinish push @push <>
【问题讨论】:
【参考方案1】:以下代码描述了一个使用POST
方法的简单示例。(如何通过POST
方法传递数据)
在这里,我描述了如何使用 POST 方法。
1.用实际的用户名和密码设置帖子字符串。
NSString *post = [NSString stringWithFormat:@"Username=%@&Password=%@",@"username",@"password"];
2. 使用NSASCIIStringEncoding
编码post 字符串以及您需要以NSData 格式发送的post 字符串。
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
您需要发送数据的实际长度。计算帖子字符串的长度。
NSString *postLength = [NSString stringWithFormat:@"%d",[postData length]];
3. 创建一个带有所有属性的 Urlrequest,例如 HTTP
方法、带有帖子字符串长度的 http 标头字段。创建URLRequest
对象并对其进行初始化。
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
设置要向该请求发送数据的 URL。
[request setURL:[NSURL URLWithString:@"http://www.abcde.com/xyz/login.aspx"]];
现在,设置 HTTP 方法(POST 或 GET)。按照您的代码中的方式编写这些行。
[request setHTTPMethod:@"POST"];
将HTTP
标头字段设置为发布数据的长度。
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
同时设置 HTTP 标头字段的编码值。
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
用postData设置urlrequest的HTTPBody
。
[request setHTTPBody:postData];
4. 现在,创建 URLConnection 对象。使用 URLRequest 对其进行初始化。
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
它返回初始化的 url 连接并开始为 url 请求加载数据。您可以使用以下 if/else 语句检查您的URL
连接是否正确完成。
if(conn)
NSLog(@"Connection Successful");
else
NSLog(@"Connection could not be made");
5. 要接收来自 HTTP 请求的数据,您可以使用 URLConnection 类参考提供的委托方法。 委托方法如下。
// This method is used to receive the data which we get using post method.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)data
// This method receives the error report in case of connection is not made to server.
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
// This method is used to process the data after connection has made successfully.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
另请参阅 This 和 This 文档了解POST
方法。
这是HTTPPost Method.源代码的最佳示例
【讨论】:
同时检查是否没有缓存。这可以解释为什么你得到一个“200”,而服务器上没有任何事情发生。 检查***.com/questions/405151/… 和/或谷歌接受的答案以获取“nsurlconnection 缓存策略” 虽然这个答案已经被接受了这么多次,但这个答案中给出的代码有很多明显的问题,在实践中会很麻烦。 @iPatel 但是我们可以使用上面给出的 post 方法代码发送图像数据吗? 很遗憾,这段代码不正确,容易受到注入攻击。如果用户在密码中碰巧有一个“&”字符,则所有其他字符都将被解析为附加的 POST 参数。故意操纵是可能的。【参考方案2】:-(void)sendingAnHTTPPOSTRequestOniOSWithUserEmailId: (NSString *)emailId withPassword: (NSString *)password
//Init the NSURLSession with a configuration
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
//Create an URLRequest
NSURL *url = [NSURL URLWithString:@"http://www.example.com/apis/login_api"];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
//Create POST Params and add it to HTTPBody
NSString *params = [NSString stringWithFormat:@"email=%@&password=%@",emailId,password];
[urlRequest setHTTPMethod:@"POST"];
[urlRequest setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
//Create task
NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
//Handle your response here
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
NSLog(@"%@",responseDict);
];
[dataTask resume];
【讨论】:
【参考方案3】:我不太清楚为什么,但只要我注释掉以下方法就可以了:
connectionDidFinishDownloading:destinationURL:
此外,我认为您不需要来自 NSUrlConnectionDownloadDelegate 协议的方法,只需要来自 NSURLConnectionDataDelegate 的方法,除非您需要一些下载信息。
【讨论】:
我确实想要下载信息,这就是为什么我有函数 connectionDidFinishDownloading:destinationURL: 显然 NSURLConnectionDownloadDelegate 仅适用于报亭应用程序......至少这是这个线程所说的:***.com/questions/6735121/…【参考方案4】:这是我在日志库中使用的方法:https://github.com/goktugyil/QorumLogs
此方法填充 Google 表单中的 html 表单。希望它对使用 Swift 的人有所帮助。
var url = NSURL(string: urlstring)
var request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
request.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.HTTPBody = postData.dataUsingEncoding(NSUTF8StringEncoding)
var connection = NSURLConnection(request: request, delegate: nil, startImmediately: true)
【讨论】:
【参考方案5】:在 iOS 上发送 HTTP POST 请求(目标 c):
-(NSString *)postexample
// SEND POST
NSString *url = [NSString stringWithFormat:@"URL"];
NSString *post = [NSString stringWithFormat:@"param=value"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:@"%d",[postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setHTTPMethod:@"POST"];
[request setURL:[NSURL URLWithString:url]];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:postData];
NSError *error = nil;
NSHTTPURLResponse *responseCode = nil;
//RESPONDE DATA
NSData *oResponseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&responseCode error:&error];
if([responseCode statusCode] != 200)
NSLog(@"Error getting %@, HTTP status code %li", url, (long)[responseCode statusCode]);
return nil;
//SEE RESPONSE DATA
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Response" message:[[NSString alloc] initWithData:oResponseData encoding:NSUTF8StringEncoding] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
[alert show];
return [[NSString alloc] initWithData:oResponseData encoding:NSUTF8StringEncoding];
【讨论】:
这是新的......在您的问题发布 4 年后得到回复:p 这个“postexample”函数比Response更快:p @DaanLuttik【参考方案6】:使用 Swift 3 或 4 您可以访问这些 http 请求进行服务器通信。
// 用于请求 POST 数据
func postAction()
//declare parameter as a dictionary which contains string as key and value combination. considering inputs are valid
let parameters = ["id": 13, "name": "jack"] as [String : Any]
//create the url with URL
let url = URL(string: "www.requestURL.php")! //change the url
//create the session object
let session = URLSession.shared
//now create the URLRequest object using the url object
var request = URLRequest(url: url)
request.httpMethod = "POST" //set http method as POST
do
request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) // pass dictionary to nsdata object and set it as request body
catch let error
print(error.localizedDescription)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
//create dataTask using the session object to send data to the server
let task = session.dataTask(with: request as URLRequest, completionHandler: data, response, error in
guard error == nil else
return
guard let data = data else
return
do
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any]
print(json)
// handle json...
catch let error
print(error.localizedDescription)
)
task.resume()
// 用于从请求中获取数据
func GetRequest()
let urlString = URL(string: "http://www.requestURL.php") //change the url
if let url = urlString
let task = URLSession.shared.dataTask(with: url) (data, response, error) in
if error != nil
print(error ?? "")
else
if let responceData = data
print(responceData) //JSONSerialization
do
//create json object from data
if let json = try JSONSerialization.jsonObject(with:responceData, options: .mutableContainers) as? [String: Any]
print(json)
// handle json...
catch let error
print(error.localizedDescription)
task.resume()
// 用于从请求中获取图片或视频等下载内容
func downloadTask()
// Create destination URL
let documentsUrl:URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first as URL!
let destinationFileUrl = documentsUrl.appendingPathComponent("downloadedFile.jpg")
//Create URL to the source file you want to download
let fileURL = URL(string: "http://placehold.it/120x120&text=image1")
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig)
let request = URLRequest(url:fileURL!)
let task = session.downloadTask(with: request) (tempLocalUrl, response, error) in
if let tempLocalUrl = tempLocalUrl, error == nil
// Success
if let statusCode = (response as? HTTPURLResponse)?.statusCode
print("Successfully downloaded. Status code: \(statusCode)")
do
try FileManager.default.copyItem(at: tempLocalUrl, to: destinationFileUrl)
catch (let writeError)
print("Error creating a file \(destinationFileUrl) : \(writeError)")
else
print("Error took place while downloading a file. Error description: %@", error?.localizedDescription ?? "");
task.resume()
【讨论】:
【参考方案7】:目标 C
使用参数发布 API 并使用 url 验证以导航是否为 json 状态为“成功”的响应键
NSString *string= [NSString stringWithFormat:@"url?uname=%@&pass=%@&uname_submit=Login",self.txtUsername.text,self.txtPassword.text];
NSLog(@"%@",string);
NSURL *url = [NSURL URLWithString:string];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"POST"];
NSURLResponse *response;
NSError *err;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
NSLog(@"responseData: %@", responseData);
NSString *str = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(@"responseData: %@", str);
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData
options:kNilOptions
error:nil];
NSDictionary* latestLoans = [json objectForKey:@"status"];
NSString *str2=[NSString stringWithFormat:@"%@", latestLoans];
NSString *str3=@"success";
if ([str3 isEqualToString:str2 ])
[self performSegueWithIdentifier:@"move" sender:nil];
NSLog(@"successfully.");
else
UIAlertController *alert= [UIAlertController
alertControllerWithTitle:@"Try Again"
message:@"Username or Password is Incorrect."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
[self.view endEditing:YES];
];
[alert addAction:ok];
[[UIView appearanceWhenContainedIn:[UIAlertController class], nil] setTintColor:[UIColor redColor]];
[self presentViewController:alert animated:YES completion:nil];
[self.view endEditing:YES];
JSON 响应 : "status":"success","user_id":"58","user_name":"dilip","result":"您已成功登录" 工作代码
**
【讨论】:
以上是关于在 iOS 上发送 HTTP POST 请求的主要内容,如果未能解决你的问题,请参考以下文章
从 iOS 9 / Swift 2.0 发送 HTTP POST 请求时,PHP 服务器没有收到正确的数据
(转)IOS http请求的get 和 post的请求的区别