Envoi d'une requête HTTP POST sur iOS

86

J'essaye d'envoyer un message HTTP avec l'application iOS que je développe mais le push n'atteint jamais le serveur bien que j'obtienne un code 200 en réponse (de l'urlconnection). Je ne reçois jamais de réponse du serveur et le serveur ne détecte pas mes messages (le serveur détecte les messages provenant d'Android)

J'utilise ARC mais j'ai défini pd et urlConnection comme forts.

Ceci est mon code pour envoyer la demande

 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];

c'est mon code pour le délégué

#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

La console imprime toujours les lignes suivantes et les lignes suivantes uniquement:

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 <>
Daan Luttik
la source

Réponses:

188

Le code suivant décrit un exemple simple d'utilisation de POSTméthode. ( Comment transmettre des données par POSTméthode )

Ici, je décris comment on peut utiliser la méthode POST.

1. Définissez la chaîne de publication avec le nom d'utilisateur et le mot de passe réels.

NSString *post = [NSString stringWithFormat:@"Username=%@&Password=%@",@"username",@"password"]; 

2. Encodez la chaîne de publication en utilisant NSASCIIStringEncodingainsi que la chaîne de publication que vous devez envoyer au format NSData.

NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; 

Vous devez envoyer la longueur réelle de vos données. Calculez la longueur de la chaîne de publication.

NSString *postLength = [NSString stringWithFormat:@"%d",[postData length]]; 

3. Créez une Urlrequest avec toutes les propriétés comme HTTPméthode, champ d'en-tête http avec la longueur de la chaîne de publication. Créez un URLRequestobjet et initialisez-le.

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; 

Définissez l'URL pour laquelle vous allez envoyer les données à cette demande.

[request setURL:[NSURL URLWithString:@"http://www.abcde.com/xyz/login.aspx"]]; 

Maintenant, définissez la méthode HTTP ( POST ou GET ). Écrivez ces lignes telles qu'elles sont dans votre code.

[request setHTTPMethod:@"POST"]; 

Définissez le HTTPchamp d'en-tête avec la longueur des données de publication.

[request setValue:postLength forHTTPHeaderField:@"Content-Length"]; 

Définissez également la valeur encodée pour le champ d'en-tête HTTP.

[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

Définissez le HTTPBodyde l'urlrequest avec postData.

[request setHTTPBody:postData];

4. Créez maintenant l'objet URLConnection. Initialisez-le avec l'URLRequest.

NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 

Il renvoie la connexion URL initialisée et commence à charger les données pour la demande d'URL. Vous pouvez vérifier si votre URLconnexion est effectuée correctement ou non en utilisant simplement l' instruction if / else comme ci-dessous.

if(conn) {
    NSLog(@"Connection Successful");
} else {
    NSLog(@"Connection could not be made");
}

5. Pour recevoir les données de la requête HTTP, vous pouvez utiliser les méthodes déléguées fournies par la référence de classe URLConnection. Les méthodes des délégués sont les suivantes.

// 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

Consultez également ceci et cette documentation pour la POSTméthode.

Et voici le meilleur exemple avec le code source de la méthode HTTPPost.

iPatel
la source
1
Vérifiez également s'il n'y a pas de mise en cache en cours. Cela expliquerait pourquoi vous avez obtenu un «200», sans que rien ne se passe sur le serveur.
Jelle
Vérifiez la réponse acceptée de stackoverflow.com/questions/405151/… et / ou google pour "nsurlconnection cache policy"
Jelle
1
Même si la réponse a été acceptée tant de fois, le code donné dans cette réponse présente un certain nombre de problèmes flagrants et sera gênant dans la pratique.
CouchDeveloper
1
@iPatel Mais pouvons-nous envoyer des données d'image en utilisant le code de méthode de publication ci-dessus.
iHulk
1
Malheureusement, ce code est incorrect et sujet aux attaques par injection. Si l'utilisateur a un caractère "&" dans le mot de passe, tous les autres caractères seront analysés comme un paramètre POST supplémentaire. Une manipulation délibérée est possible.
ge0rg
4
-(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];
}
Mannam Brahmam
la source
2

Je ne sais pas vraiment pourquoi, mais dès que je commente la méthode suivante, cela fonctionne:

connectionDidFinishDownloading:destinationURL:

De plus, je ne pense pas que vous ayez besoin des méthodes du protocole NSUrlConnectionDownloadDelegate, uniquement celles de NSURLConnectionDataDelegate, sauf si vous voulez des informations de téléchargement.

nickygerritsen
la source
Je veux les informations de téléchargement, c'est pourquoi j'ai la fonction connectionDidFinishDownloading: destinationURL:
Daan Luttik
1
Apparemment, NSURLConnectionDownloadDelegate ne fonctionne que dans les applications Kiosque .... Au moins, c'est ce que dit ce fil: stackoverflow.com/questions/6735121/…
nickygerritsen
2

Voici la méthode que j'ai utilisée dans ma bibliothèque de journalisation: https://github.com/goktugyil/QorumLogs

Cette méthode remplit les formulaires html dans Google Forms. J'espère que cela aide quelqu'un qui utilise 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)
Esqarrouth
la source
1

Envoi d'une requête HTTP POST sur iOS (Objectif 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];
}
Ronny Morán
la source
This is new ... Obtenir des réponses 4 ans après la publication de votre question: p
Daan Luttik
Cette fonction "postexample" est plus rapide que Réponse : p @DaanLuttik
Ronny Morán
1

En utilisant Swift 3 ou 4, vous pouvez accéder à ces requêtes http pour la communication avec le serveur.

// Pour les données POST à ​​demander

 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() }

// Pour obtenir les données de la requête

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()
    }
}

// Pour obtenir le contenu de téléchargement comme une image ou une vidéo à partir de la demande

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()

}
Technologie
la source
1

Objectif c

Publier l'API avec les paramètres et valider avec l'URL pour naviguer si la
clé de réponse json avec le statut: "succès"

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];
      }

Réponse JSON : {"status": "success", "user_id": "58", "user_name": "dilip", "result": "Vous avez été connecté avec succès"} Code de travail

**

Dilip Tiwari
la source