Swift HTTP post Request dataUsingEncoding 会错误地生成字符串


Swift HTTP Post Request dataUsingEncoding malformes the string

我目前正在与问这个问题的家伙一起开发一个应用程序:发布请求总是用可选文本包装他正在编写iOS部分,我正在编写Android部分,我完全不知道整个Swift的事情是什么让iOS编码有点困难,因为他几乎没有编程经验。

现在来问问题:我们正在向我编写的 php 脚本发送 POST 请求,该脚本获取发布的用户名和密码,并再次向应用程序发送 json 响应。

$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);
}

例如,如果用户名或密码为空,我们应该得到以下响应:

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

对于Android,这非常有效,我们可以处理响应。

但是在 iOS 中,当我们对字符串进行编码时,它会将我们发送到 php 脚本的整个字符串转换为:

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

由于 php 脚本需要这样的数据:

username=xyz&password=xyz

它当然不起作用。

那么我们如何才能将这种蹩脚的十六进制代码转换为我们想要的东西,或者我们如何才能防止这种畸形。

提前致谢:D

编辑

斯威夫特代码:

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 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( 你从服务器扔掉答案...

b( 熟悉调试器并检查 postString 的内容;它从来都不是有效的 JSON,因此您不能指望转换成功。

c(不要混合发送和接收部分,而是解决一个又一个问题。

d( 当您将结果作为评论内联发布时,回答要容易得多。

用那行:

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

您正在使用 POST 请求的参数覆盖在完成处理程序中返回的数据变量。只需删除此行即可。然后,您还必须在下面几行中解开数据参数的包装,只需在数据后插入"!"即可。(更好的代码风格是在闭包开始时使用可选绑定,但"!"只是让它;)工作(

参数未正确编码。

若要设置包含 POST 请求参数的内容类型application/x-www-form-urlencoded,应使用帮助程序类 NSURLComponents

首先,创建一个NSURLQueryItems数组,例如:

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

其中parameter是一个元组数组或参数字典,其元素(namevalue(是字符串。

然后将此数组设置为NSURLComponents实例:

        let urlQueryComponent = NSURLComponents()
        urlQueryComponent.queryItems = queryItems

编码的"查询"字符串可以如下所示:

        let queryString = urlQueryComponent.percentEncodedQuery!

然后作为 NSData 表示形式:

        let data = queryString.dataUsingEncoding(NSUTF8StringEncoding)!

好问题。好消息是,这似乎是一个常见而简单的错误。在request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)行中,该编码的结果是可选的,而不是您必须发送的 JSON 或数据对象。这意味着对象在那里,但它被包装在一个允许编码结果的属性中 nil .

首先,您需要删除此行:

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

因为你实际上是在覆盖返回的数据。

好的,要解决可选问题,有一些替代方案:

首先也是最推荐的是解包值并设置为httpbody,如下所示:

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
}

其次,您可以直接构造JSON并对其进行编码(尽管我不确定这是您服务器期望的格式(:

let jsonDic: [String: Any] = ["username": username, "password": password]
do {
 let jsonData = try JSONSerialization.data(withJSONObject: json)
catch {
 //treat the error here
}
request.HTTPBody = jsonData
第三,在生产中(

仅用于测试(中推荐的第三种(根本不推荐(是用"!"强制解包值,如下所示:

request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)!