Swift 4 以 x-www-form-urlencoded 形式发送 POST 请求

6 浏览
0 Comments

Swift 4 以 x-www-form-urlencoded 形式发送 POST 请求

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

这是处理我的urlSession请求(包括GET和POST)的结构体

XHR.swift

struct XHR {

enum Result {

case success(T)

case failure(Error)

}

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

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

// 设置URL请求

guard let url = URL.init(string: file) else {

print("错误:无法创建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)

}

// 设置会话

let config = URLSessionConfiguration.default

let session = URLSession(configuration: config)

// 与let session = URLSession.shared不同

// 发送请求

let task = session.dataTask(with: urlRequest, completionHandler: {

(data, response, error) in

DispatchQueue.main.async { // 正确

guard let responseData = data else {

print("错误:未收到数据")

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("将数据转换为JSON时出错")

//print(error)

completionHandler(.failure(error))

}

}

})

task.resume()

}

}

这是发送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.stride)

}

static func unarchive(d:Data) -> User {

guard d.count == MemoryLayout.stride else {

fatalError("BOOM!")

}

var w:User?

d.withUnsafeBytes({(bytes: UnsafePointer)->Void in

w = UnsafePointer(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) in

switch result {

case .failure(let error):

completionHandler(.failure(error))

case .success(let user):

//let convertedThing = User.unarchive(d: user)

completionHandler(.success(user))

}

}

}

我这样调用它:

videoViewModel.login(username: "rexhin", password: "bonbon") { (result: VideoViewModel.Login) in

switch result {

case .failure(let error):

print("错误")

case .success(let user):

print(user)

}

}

从PHP中我可以看到成功提交了一个POST请求,但当我尝试通过$_POST["username"]来获取username字段时,我得到Undefined index:的错误。

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

0
0 Comments

问题的原因是需要发送一个x-www-form-urlencoded格式的POST请求,但是在Swift 4中默认的编码方式是JSON编码,因此需要找到一种方法来实现x-www-form-urlencoded编码。

解决方法是使用Alamofire / Vapor库中的URLEncodedFormEncoder.swift文件来进行编码。具体步骤如下:

1. 将URLEncodedFormEncoder.swift文件添加到你的项目中,该文件是来自Alamofire / Vapor库的自定义URLEncodedFormEncoder。

2. 让你的模型遵循Swift的Encodable协议,就像你在进行JSON编码时一样。

3. 使用与JSON编码时相同的方式对模型进行编码。

示例代码如下:

// 创建请求模型

let requstModel = OpenIDCTokenRequest(

clientId: clientId,

clientSecret: clientSecret,

username: username,

password: password

)

// 使用URLEncodedFormEncoder对模型进行编码

guard let requestData: Data = try? URLEncodedFormEncoder().encode(requstModel) else {

return // 处理编码错误

}

通过以上方法,我们可以在Swift 4中发送x-www-form-urlencoded格式的POST请求。

0
0 Comments

问题的原因是你将User.archive(w: thing)的结果作为请求体中的data,这可能永远不会成功。一般来说,你的archive(w:)unarchive(d:)不会生成任何有用的结果,最好立即将它们移除。

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

可以尝试这样做:

func login(username: String, password: String, completionHandler: (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

//...

}

}

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

是的,但是我每次发送POST请求都需要手动这样做。有没有办法将一个结构体转换为"username=\(username)&password=\(password)"

是的,需要手动转换。如果你想咨询关于任何结构体的问题,那是另一个问题。在这个问题中,你写的是this struct

如果username或password的值需要进行URL编码,这种方法可能不起作用。

谢谢你的澄清。在The example above is ...部分中也有提到这一点,但你的评论更好一些。

0
0 Comments

问题的原因是作者在使用Swift 4发送POST请求时遇到了表单数据的问题,作者尝试了使用Alamofire库临时解决该问题。但最终作者找到了这段代码,并发现它可以通过纯编码的方式传递参数。感谢作者的分享。

解决方法是作者使用了Swift 4中的URLSession来发送POST请求。首先,作者创建了一个URL对象,用于指定请求的URL地址。然后,作者获取了用户名和密码的值,并将其拼接成x-www-form-urlencoded格式的字符串。接下来,作者创建了一个URLRequest对象,并设置了请求的方法为POST,设置了请求的Content-Type为application/x-www-form-urlencoded,并设置了Accept-Language字段。然后,作者将拼接好的数据作为请求的httpBody。然后,作者创建了一个URLSession对象,并使用该对象创建了一个dataTask,用于发送请求。在请求完成后的回调中,作者首先判断是否有错误发生,如果有则打印错误信息。然后,作者判断是否有响应数据,如果有则打印"here in response"。最后,作者将响应数据转换为字符串,并打印出来。

这段代码解决了作者在使用Swift 4发送POST请求时遇到的x-www-form-urlencoded表单数据的问题,通过纯编码的方式传递参数。作者将这段代码与我们分享,并表示这段代码对解决该问题非常有用。

0