在 iOS 上发送 HTTP POST 请求

Posted

技术标签:

【中文标题】在 iOS 上发送 HTTP POST 请求【英文标题】:Sending an HTTP POST request on iOS 【发布时间】:2013-03-22 21:13:06 【问题描述】:

我正在尝试使用我正在开发的 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","re​​sult":"您已成功登录" 工作代码

**

【讨论】:

以上是关于在 iOS 上发送 HTTP POST 请求的主要内容,如果未能解决你的问题,请参考以下文章

从 iOS 9 / Swift 2.0 发送 HTTP POST 请求时,PHP 服务器没有收到正确的数据

ios如何使用http post请求发送json数据

(转)IOS http请求的get 和 post的请求的区别

三个例子 —JAVA发送http get/post请求,调用http接口方法

Java 发送http post 请求

后台发送http请求通用方法,包括get和post