简体   繁体   中英

Swift HTTP Post Request dataUsingEncoding malformes the string

I am currently developing an App with the dude who asked this question: Post request always wrapped by optional text He is programming the iOS part, I am programming the Android part and I have absolutely no idea of this whole Swift thing what makes coding in iOS kinda hard, because he has almost no programming experience.

Now to the question: We are sending a POST request to a php script I wrote that gets the posted username and password and sends a json response to the app again.

$username = $_POST['username'];
$password = $_POST['password'];
if (!empty($username) && !empty($password)) {
    $encrypted_password = md5($password);
    $user -> login($username,$encrypted_password);
} else {
    $json['error'] = 'You must fill all fields!';
    echo json_encode($json);
    mysqli_close($this->connection);
}

For example, if the username or password are empty we should get this response:

{"error":"You must fill all fields!"}

For Android this works perfectly and we can work with the response.

But in iOS when we encode the String it converts the whole string we send to the php script into this:

Optional(<75736572 6e616d65 3d612670 61737377 6f72643d 61>)

Since the php script wants the data like this:

username=xyz&password=xyz

It does of course not work.

So how can we convert this crappy hex-code into what we want or how can we even prevent this malformation.

Thanks in advance :D

EDIT

Swift-Code:

let username = UsernameTextField.text ?? ""
        let password = PasswordTextField.text ?? ""
        
        if(username.isEmpty || password.isEmpty) {return; }
        
        
        
        let request = NSMutableURLRequest (URL: NSURL(string: "http://myip/loginregister.php")!)
        request.HTTPMethod = "POST"
        request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField:"Content-Type")
        let postString = "username=\(username)&password=\(password)"
        request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
        let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
            guard error == nil && data != nil else {
                // check for fundamental networking error
                print("error=\(error)")
                return
            }
            
            let data = postString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
            
            
            do {
                if let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? NSDictionary {
                    let success = json["success"] as? Int                                 
                    print("Success: \(success)")
                } else {
                    let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)   
                    print("Error could not parse JSON: \(jsonStr)")
                }
            } catch let parseError {
                print(parseError)                                                      `JSONObjectWithData`
                let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
                print("Error could not parse JSON: '\(jsonStr)'")
            }
        }
        
        task.resume()

Error-Message:

Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
Error could not parse JSON: 'Optional(username=a&password=a)'

a) You throw away the answer from the server...

b) Get familiar with the debugger and examine the contents of postString; it is never valid JSON, so you can't expect conversion to succeed.

c) Don't mix the send and receive part, but solve one problem after another.

d) It is much easier to answer when you post your results in-line as comments.

With that line:

let data = postString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!

you are overwriting the data variable that is given back in the completion handler with the arguments of your post request. Just delete this line. Then you also have to unwrap the data parameter a few lines below, just insert a '!' after data. (Better code style would be to use optional binding at the begin of the closure, but the '!' just makes it working ;))

Your parameters are not properly encoded.

In order to setup a content type application/x-www-form-urlencoded containing parameters for a POST request, you should use the helper class NSURLComponents .

First, create an array of NSURLQueryItems , for example:

        var queryItems = [NSURLQueryItem]()
        self.parameters.forEach { (name, value) in
            queryItems.append(NSURLQueryItem(name: name, value: value))
        }

where parameter is an array of tuples or a dictionary of parameters, whose elements ( name and value ) are Strings.

Then set this array to a NSURLComponents instance:

        let urlQueryComponent = NSURLComponents()
        urlQueryComponent.queryItems = queryItems

The encoded "query" string can be obtained as shown below:

        let queryString = urlQueryComponent.percentEncodedQuery!

and then as a NSData representation:

        let data = queryString.dataUsingEncoding(NSUTF8StringEncoding)!

Good question. The good news is this seems to be a common and simple mistake. In the line request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding) the result of that encoding is an optional and not the JSON or Data object you must send. This means the object is there, but it is wrapped in a property that allows the result of the encoding to be nil .

First of all, you need to delete this line:

let data = postString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!

Because you're literally overwriting the data that came back.

Ok, to fix the optional problem, there are some alternatives:

First and most recommended is to unwrap the value and set as the httpbody like this:

if let unWrappedValue = postString.dataUsingEncoding(NSUTF8StringEncoding) {
 request.HTTPBody = unWrappedValue
}
else {
 //if the encoding fails, treat the error here before sending any value as the body
}

Second, you can construct the JSON directly and than encode it (although I'm not sure this is the format you server is expecting):

let jsonDic: [String: Any] = ["username": username, "password": password]

do {
 let jsonData = try JSONSerialization.data(withJSONObject: json)
catch {
 //treat the error here
}

request.HTTPBody = jsonData

Third and NOT AT ALL recommended in production (just for test) is to force unwrap the value with "!" like this:

request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM