web-dev-qa-db-fra.com

POST demande en utilisant application/x-www-form-urlencoded

Le développeur principal avait donné ces instructions dans les requêtes POST:

  1. Route: {url}/{nom_app/{contrôleur}/{action}
  2. Le contrôleur et l'action doivent être sur les petites capitales. 
  3. Lien de test de l'API: http:* ** * ** * ** * ** * ***
  4. La demande doit être utiliser la méthode POST.
  5. Les paramètres doivent être transmis via le corps du contenu de la demande (FormUrlEncodedContent).
  6. Les paramètres doivent être au format JSON.
  7. Les paramètres sont sensibles à la clé.

N'ayant aucune expérience avec le numéro 5 dans le protocole, j'ai cherché et fini avec mon code.

-(id)initWithURLString:(NSString *)URLString withHTTPMEthod:(NSString *)method withHTTPBody:(NSDictionary *)body {

    _URLString = URLString;
    HTTPMethod = method;
    HTTPBody = body;

    //set error message
    errorMessage = @"Can't connect to server at this moment. Try again later";
    errorTitle = @"Connection Error";

    return  self;
}


-(void)fireConnectionRequest {

    NSOperationQueue *mainQueue = [[NSOperationQueue alloc] init];
    [mainQueue setMaxConcurrentOperationCount:5];

    NSError *error = Nil;

    NSURL *url = [NSURL URLWithString:_URLString];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];

    NSData *sendData = [NSJSONSerialization dataWithJSONObject:HTTPBody options:NSJSONWritingPrettyPrinted error:&error];
    [request setHTTPMethod:@"POST"];

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

    [request setHTTPBody: sendData];
    [NSURLConnection connectionWithRequest:request delegate:self];

    NSString *jsonString = [[NSString alloc]initWithData:sendData encoding:NSUTF8StringEncoding];


    //fire URL connectiion request
    [NSURLConnection sendAsynchronousRequest:request queue:mainQueue completionHandler:^(NSURLResponse *response, NSData *responseData, NSError *error) {

        //get the return message and transform to dictionary
        NSString *data = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
        returnMessage = [NSJSONSerialization JSONObjectWithData: [data dataUsingEncoding:NSUTF8StringEncoding]
                                                        options: NSJSONReadingMutableContainers
                                                          error:&error];


        //check return message
        if (!error) {
            [delegate returnMessageForTag:self.tag];

        }
        else {
            [delegate returnErrorMessageForTag:self.tag];
        }

    }];

}

Je passe un dictionnaire au format JSON. il convient que j'ai pu transmettre les bonnes données. Et j’ai pu me connecter à l’API, mais elle renvoie toujours «ÉCHEC» lorsque j’essaie d’envoyer des données à enregistrer. Il n'y a pas de problèmes de connexion, mais je n'ai pas réussi à transférer les données.

Le développeur Android utilisant la même API n’a aucun problème avec cela, mais n’a pas pu m'aider car il ne connaît pas iOS.

Qu'est-ce que je rate?

19
jmac

Essayez comme ce code

Objectif c

NSString *post =[NSString stringWithFormat:@"AgencyId=1&UserId=1&Type=1&Date=%@&Time=%@&Coords=%@&Image=h32979`7~U@)01123737373773&SeverityLevel=2",strDateLocal,strDateTime,dict];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:@"%d",[postData length]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://google/places"]]];
[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:postData];
NSError *error;
NSURLResponse *response;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *str=[[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];

Swift 2.2

var post = "AgencyId=1&UserId=1&Type=1&Date=\(strDateLocal)&Time=\(strDateTime)&Coords=\(dict)&Image=h32979`7~U@)01123737373773&SeverityLevel=2"
var postData = post.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: true)!
var postLength = "\(postData.length)"
var request = NSMutableURLRequest()
request.URL = NSURL(string: "http://google/places")!
request.HTTPMethod = "POST"
request.setValue(postLength, forHTTPHeaderField: "Content-Length")
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.HTTPBody = postData
NSError * error
NSURLResponse * response
var urlData = try! NSURLConnection.sendSynchronousRequest(request, returningResponse: response)!
var str = String(data: urlData, encoding: NSUTF8StringEncoding)

Swift 3.0

let jsonData = try? JSONSerialization.data(withJSONObject: kParameters)
    let url: URL = URL(string: "Add Your API URL HERE")!
    print(url)
    var request: URLRequest = URLRequest(url: url)
    request.httpMethod = "POST"
    request.httpBody = jsonData
    request.setValue(Constant.UserDefaults.object(forKey: "Authorization") as! String?, forHTTPHeaderField: "Authorization")
    request.setValue(Constant.kAppContentType, forHTTPHeaderField: "Content-Type")
    request.setValue(Constant.UserAgentFormat(), forHTTPHeaderField: "User-Agent")

    let task = URLSession.shared.dataTask(with: request, completionHandler: { data, response, error in

        if data != nil {

            do {
                let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! NSDictionary
                print(json)
            } catch let error as NSError {
                print(error)
            }
        } else {
            let emptyDict = NSDictionary()
        }
    })
    task.resume()

J'espère que ce code vous sera utile.

33
Darshan Kunjadiya

@fatihyildizhan

pas assez de réputation pour commenter directement votre réponse donc cette réponse.

Swift 1.2

let myParams = "username=user1&password=12345"
let postData = myParams.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: true)
let postLength = String(format: "%d", postData!.length)

var myRequest = NSMutableURLRequest(URL: self.url)
myRequest.HTTPMethod = "POST"
myRequest.setValue(postLength, forHTTPHeaderField: "Content-Length")
myRequest.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
myRequest.HTTPBody = postData

var response: AutoreleasingUnsafeMutablePointer<NSURLResponse?> = nil

Ce code ci-dessus fonctionne parfaitement dans mon cas.

7
Muarl

Avec Swift 3, laissez jsonData = essayer? JSONSerialization.data (withJSONObject: kParameters) n'a pas fonctionné correctement pour moi, j'ai donc dû copier la solution AlamoFire ...

let body2 = ["username": "[email protected]",
        "password": "111",
        "client_secret":"7E",
        "grant_type":"password"]

let data : Data = query(body2).data(using: .utf8, allowLossyConversion: false)!
var request : URLRequest = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField:"Content-Type");
request.setValue(NSLocalizedString("lang", comment: ""), forHTTPHeaderField:"Accept-Language");
request.httpBody = data 

do {...}

}

public func queryComponents(fromKey key: String, value: Any) -> [(String, String)] {
        var components: [(String, String)] = []

        if let dictionary = value as? [String: Any] {
            for (nestedKey, value) in dictionary {
                components += queryComponents(fromKey: "\(key)[\(nestedKey)]", value: value)
            }
        } else if let array = value as? [Any] {
            for value in array {
                components += queryComponents(fromKey: "\(key)[]", value: value)
            }
        } else if let value = value as? NSNumber {
            if value.isBool {
                components.append((escape(key), escape((value.boolValue ? "1" : "0"))))
            } else {
                components.append((escape(key), escape("\(value)")))
            }
        } else if let bool = value as? Bool {
            components.append((escape(key), escape((bool ? "1" : "0"))))
        } else {
            components.append((escape(key), escape("\(value)")))
        }

        return components
    }


    public func escape(_ string: String) -> String {
        let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
        let subDelimitersToEncode = "!$&'()*+,;="

        var allowedCharacterSet = CharacterSet.urlQueryAllowed
        allowedCharacterSet.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")

        var escaped = ""

        if #available(iOS 8.3, *) {
            escaped = string.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? string
        } else {
            let batchSize = 50
            var index = string.startIndex

            while index != string.endIndex {
                let startIndex = index
                let endIndex = string.index(index, offsetBy: batchSize, limitedBy: string.endIndex) ?? string.endIndex
                let range = startIndex..<endIndex

                let substring = string.substring(with: range)

                escaped += substring.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? substring

                index = endIndex
            }
        }
        return escaped
    }

Et une extension:

extension NSNumber {
fileprivate var isBool: Bool { return CFBooleanGetTypeID() == CFGetTypeID(self) }}

C'est temporaire, cela doit être une meilleure solution ...

J'espère que ça aidera ...

3
Diego Renau

Swift propose une fonction permettant de coder l'URL du corps, mais ce n'est pas là que vous pourriez vous attendre à le trouver. Pour l'étape 5 de la question initiale, une fois que vous avez les paires clé-valeur dans une structure, voici une alternative courte et simple pour l'encodage (Swift 4.2):

var urlParser = URLComponents()
urlParser.queryItems = [
    URLQueryItem(name: "name", value: "Tim Tebow"),
    URLQueryItem(name: "desc", value: "Gators' QB")
]
let httpBodyString = urlParser.percentEncodedQuery

Collez-le dans un terrain de jeu Xcode et ajoutez print(httpBodyString!). Dans la sortie, vous verrez:

name=Tim%20Tebow&desc=Gators'%20QB

Remarque: ceci concerne Content-Type: application/x-www-form-urlencoded pour la méthode HTTP POST avec un ensemble de valeurs de formulaire de base (c'est-à-dire, pas de données binaires et non en plusieurs parties)

1
Jeff Collier

Est-il possible de convertir ce code en Swift? J'ai déjà essayé mais je ne pouvais pas le supporter. Peut-être que ce bloc de code peut vous aider. Merci.

    let myParams:NSString = "username=user1&password=12345"
    let myParamsNSData:NSData = NSData(base64EncodedString: myParams, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)!
    let myParamsLength:NSString = NSString(UTF8String: myParamsNSData.length)
    let myRequest: NSMutableURLRequest = NSURL(fileURLWithPath: self.url)
    myRequest.HTTPMethod = "POST"
    myRequest.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
    myRequest.HTTPBody = myParamsNSData
    var data2: NSData!
    var error2: NSError!
0
fatihyildizhan

Swift 4.2

    func percentEscapeString(_ string: String) -> String {
            var characterSet = CharacterSet.alphanumerics
            characterSet.insert(charactersIn: "-._* ")
            return string
              .addingPercentEncoding(withAllowedCharacters: characterSet)!
              .replacingOccurrences(of: " ", with: " ")
              .replacingOccurrences(of: " ", with: " ", options: [], range: nil)
              .replacingOccurrences(of: "\"", with: "", options: NSString.CompareOptions.literal, range:nil)
          }
//    Set encoded values to Dict values you can decode keys if required
    dictData.forEach { (key, value) in
              if let val = value as? String {
                dictData[key] = self.percentEscapeString(val)
              } else {
                dictData[key] = value
              }
            }

Cela a fonctionné pour moi et voici le lien source https://Gist.github.com/HomerJSimpson/80c95f0424b8e9718a40

0
GSK