我想向我的php 7服务器发送一个POST请求,该服务器接受application/x-www-form-urlencoded
的数据。我拥有的数据在Struct中,我希望在提交时将此结构的每个属性作为参数。
这是处理我的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()
}
}
这是向服务器发送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))
}
}
}
我称之为:
videoViewModel.login(username: "rexhin", password: "bonbon") { (result: VideoViewModel.Login) in
switch result {
case .failure(let error):
print("error")
case .success(let user):
print(user)
}
}
从PHP我可以看到POST请求已成功提交但当我尝试通过username
获取$_POST["username"]
字段时,我得到Undefined index:
此处可以看到该应用的完整代码https://gitlab.com/rexhin/ios-kida.git
答案 0 :(得分:4)
您正在传递User.archive(w: thing)
的结果作为请求正文中嵌入的data
,这可能永远不会有效。通常,您的archive(w:)
和unarchive(d:)
永远不会产生任何有用的结果,您最好立即删除它们。
如果要传递需要x-www-form-urlencoded
的参数,则需要创建类似URL查询的字符串。
尝试这样的事情:
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
//...
}
}
上面的示例有点简化,您可能需要在将username
和/或password
嵌入字符串之前将其转义,此时它们可以包含一些特殊字符。你可以在网上找到很多关于它的文章。
答案 1 :(得分:1)
引用此post
在PHP中,从未设置的变量或数组元素是 不同于其值为null的人;试图访问这样的 未设置的值是运行时错误。
当您尝试访问未设置的变量或数组元素时,会发生未定义的索引错误。您应该使用函数isset以安全地从POST正文访问用户名参数。在PHP文件中尝试以下代码。
if (isset($_POST["username"]))
{
$user= $_POST["username"];
echo 'Your Username is ' . $user;
}
else
{
$user = null;
echo "No user name found";
}
答案 2 :(得分:0)
我在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()
}
答案 3 :(得分:0)
另一种方法如下:
将 URLEncodedFormEncoder.swift 添加到您的项目中。这是来自 Alamofire / Vapor 的自定义 URLEncodedFormEncoder。
使您的模型符合原生 Swift Encodable 协议,就像您使用 JSON 编码一样。
像在 json 编码期间一样对模型进行编码
// example
let requstModel = OpenIDCTokenRequest(
clientId: clientId,
clientSecret: clientSecret,
username: username,
password: password
)
guard let requestData: Data = try? URLEncodedFormEncoder().encode(requstModel) else {
return // handle encoding error
}