xcode Swift 4 将 POST 请求作为 x-www-form-urlencoded 发送

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/48720925/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 10:33:07  来源:igfitidea点击:

Swift 4 send POST request as x-www-form-urlencoded

iosswiftxcodeswift4

提问by Rexhin Hoxha

I want to send a POST request to my php 7 server which accepts data as application/x-www-form-urlencoded. The data I have is inside a Struct and I want to get every property of this struct as a parameter when I submit it.

我想向我的 php 7 服务器发送一个 POST 请求,它接受数据为application/x-www-form-urlencoded. 我拥有的数据在 Struct 中,我想在提交时将该结构的每个属性作为参数获取。

This is the struct which handles my urlSession requests both GET and POST XHR.swift

这是处理我的 urlSession 请求 GET 和 POST 的结构 XHR.swift

struct XHR {

    enum Result<T> {
        case success(T)
        case failure(Error)
    }

    func urlSession<T>(method: String? = nil, file: String, data: Data? = nil, completionHandler: @escaping (Result<T>) -> Void) where T: Codable {

        let file = file.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!

        // Set up the URL request
        guard let url = URL.init(string: file) else {
            print("Error: cannot create URL")
            return
        }

        var urlRequest = URLRequest(url: url)

        if method == "POST" {
            urlRequest.httpMethod = "POST";
            urlRequest.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
            urlRequest.httpBody = data
            print(urlRequest.httpBody)
        }

        // set up the session
        let config = URLSessionConfiguration.default
        let session = URLSession(configuration: config)
        // vs let session = URLSession.shared

        // make the request
        let task = session.dataTask(with: urlRequest, completionHandler: {
            (data, response, error) in

            DispatchQueue.main.async { // Correct

                guard let responseData = data else {
                    print("Error: did not receive data")
                    return
                }

                let decoder = JSONDecoder()
                print(String(data: responseData, encoding: .utf8))
                do {
                    let todo = try decoder.decode(T.self, from: responseData)
                    completionHandler(.success(todo))
                } catch {
                    print("error trying to convert data to JSON")
                    //print(error)
                    completionHandler(.failure(error))
                }
            }
        })
        task.resume()
    }

}

This is the functions which sends a POST request to the server: VideoViewModel.swift

这是向服务器发送 POST 请求的函数: VideoViewModel.swift

struct User: Codable {
    let username: String
    let password: String

    static func archive(w:User) -> Data {
        var fw = w
        return Data(bytes: &fw, count: MemoryLayout<User>.stride)
    }

    static func unarchive(d:Data) -> User {
        guard d.count == MemoryLayout<User>.stride else {
            fatalError("BOOM!")
        }

        var w:User?
        d.withUnsafeBytes({(bytes: UnsafePointer<User>)->Void in
            w = UnsafePointer<User>(bytes).pointee
        })
        return w!
    }
}

enum Login {
    case success(User)
    case failure(Error)
}

func login(username: String, password: String, completionHandler: @escaping (Login) -> Void) {
    let thing = User(username: username, password: password)
    let dataThing = User.archive(w: thing)

    xhr.urlSession(method: "POST", file: "https://kida.al/login_register/", data: dataThing) { (result: XHR.Result<User>) in
        switch result {
        case .failure(let error):
            completionHandler(.failure(error))
        case .success(let user):
            //let convertedThing = User.unarchive(d: user)
            completionHandler(.success(user))
        }
    }
}

And I call it like this:

我这样称呼它:

videoViewModel.login(username: "rexhin", password: "bonbon") { (result: VideoViewModel.Login) in
    switch result {
    case .failure(let error):
        print("error")

    case .success(let user):
        print(user)
    }
}

From PHP I can see that a POST request is submitted successfully but when I try to get the usernamefield by doing $_POST["username"]I get Undefined index:

从 PHP 我可以看到 POST 请求已成功提交,但是当我尝试username通过执行获取该字段时,$_POST["username"]我得到Undefined index:

Full code of the app can be seen here https://gitlab.com/rexhin/ios-kida.git

可以在此处查看应用程序的完整代码https://gitlab.com/rexhin/ios-kida.git

回答by OOPer

You are passing the result of User.archive(w: thing)as the dataembedded in the request body, which may never work. Generally, your archive(w:)and unarchive(d:)would never generate any useful results and you should better remove them immediately.

您将结果User.archive(w: thing)作为data嵌入在请求正文中的形式传递,这可能永远不会起作用。通常,您的archive(w:)unarchive(d:)永远不会产生任何有用的结果,您最好立即将其删除。

If you want to pass parameters where x-www-form-urlencodedis needed, you need to create a URL-query-like string.

如果你想在x-www-form-urlencoded需要的地方传递参数,你需要创建一个类似 URL 查询的字符串。

Try something like this:

尝试这样的事情:

func login(username: String, password: String, completionHandler: @escaping (Login) -> Void) {
    let dataThing = "username=\(username)&password=\(password)".data(using: .utf8)

    xhr.urlSession(method: "POST", file: "https://kida.al/login_register/", data: dataThing) { (result: XHR.Result<User>) in
        //...
    }
}

The example above is a little bit too simplified, that you may need to escape usernameand/or passwordbefore embedding it in a string, when they can contain some special characters. You can find many articles on the web about it.

上面的例子有点过于简化,当它们可以包含一些特殊字符时,您可能需要转义username和/或password在将其嵌入字符串之前。你可以在网上找到很多关于它的文章。

回答by Rizwan Ahmed

Quoting from this post

引自这篇文章

In PHP, a variable or array element which has never been set is different from one whose value is null; attempting to access such an unset value is a runtime error.

在 PHP 中,从未设置过的变量或数组元素与值为 null 的变量或数组元素不同;试图访问这样一个未设置的值是一个运行时错误。

The Undefined index error occurs when you try to access an unset variable or an array element. You should use function isset inorder to safely access the username param from the POST body. Try the below code in your PHP file.

当您尝试访问未设置的变量或数组元素时,会发生未定义索引错误。您应该使用函数 isset 以便从 POST 正文安全地访问用户名参数。在您的 PHP 文件中尝试以下代码。

if (isset($_POST["username"]))
{
  $user= $_POST["username"];
  echo 'Your Username is ' . $user;
} 
else 
{
  $user = null;
  echo "No user name found";
}

回答by Mohammad Muddasir

I used below code in swift 4

我在 swift 4 中使用了下面的代码

  guard let url = URL(string: "http://192.168.88.129:81/authenticate") else {
        return
    }


    let user1 = username.text!
    let pass = passwordfield.text!
    print(user1)
    print(pass)
    let data : Data = "username=\(user1)&password=\(pass)&grant_type=password".data(using: .utf8)!
    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

    print("one called")

    let config = URLSessionConfiguration.default
    let session = URLSession(configuration: config)
    // vs let session = URLSession.shared
      // make the request
    let task = session.dataTask(with: request, completionHandler: {
        (data, response, error) in

         if let error = error
        {
            print(error)
        }
         else if let response = response {
            print("her in resposne")

        }else if let data = data
         {
            print("here in data")
            print(data)
        }

        DispatchQueue.main.async { // Correct

            guard let responseData = data else {
                print("Error: did not receive data")
                return
            }

            let decoder = JSONDecoder()
            print(String(data: responseData, encoding: .utf8))
            do {
              //  let todo = try decoder.decode(T.self, from: responseData)
              //  NSAssertionHandler(.success(todo))
            } catch {
                print("error trying to convert data to JSON")
                //print(error)
              //  NSAssertionHandler(.failure(error))
            }
        }
    })
    task.resume()


}