Swift iOS应用连接数据库遇HTTP 500错误,请求排查
iOS应用调用PHP接口返回HTTP 500错误排查
开发简易iOS应用,功能是获取用户输入的userid传入数据库。单独测试PHP向数据库插入数据时功能正常,但通过Swift调用该PHP接口时,Xcode返回HTTP 500错误,无法完成数据插入。以下是相关代码及排查方案:
Swift代码(NextViewController.swift)
// // NextSecondViewController.swift // DepressionApp1 // // Created by Ashok Nambisan on 12/2/22. // import UIKit import Foundation struct ResponseObject<T: Decodable>: Decodable { let form: T } struct Foo: Decodable { let name: String } extension Dictionary { func percentEncoded() -> Data? { map { key, value in let escapedKey = "\(key)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? "" let escapedValue = "\(value)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? "" return escapedKey + "=" + escapedValue } .joined(separator: "&") .data(using: .utf8) } } extension CharacterSet { static let urlQueryValueAllowed: CharacterSet = { let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4 let subDelimitersToEncode = "!$&'()*+,;=" var allowed: CharacterSet = .urlQueryAllowed allowed.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)") return allowed }() } class NextViewController: UIViewController { let URL = "" @IBOutlet var Text: UITextView! override func viewDidLoad() { super.viewDidLoad() initializeHideKeyboard() } func initializeHideKeyboard(){ //Declare a Tap Gesture Recognizer which will trigger our dismissMyKeyboard() function let tap: UITapGestureRecognizer = UITapGestureRecognizer( target: self, action: #selector(dismissMyKeyboard)) //Add this tap gesture recognizer to the parent view view.addGestureRecognizer(tap) } @objc func dismissMyKeyboard(){ //endEditing causes the view (or one of its embedded text fields) to resign the first responder status. //In short- Dismiss the active keyboard. view.endEditing(true) } @IBOutlet weak var labelf: UILabel! @IBOutlet weak var textg: UITextField! @IBAction func Submit(_ sender: Any) { //created NSURL let url = Foundation.URL(string: "http://ashok.local:8888/insert.php")! //creating NSMutableURLRequest var request = URLRequest(url: url) request.httpMethod = "POST" //setting the method to post request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Accept") //getting values from text fields print(textg.text) let parameters: [String: Any] = [ "userid": textg.text ] request.httpBody = parameters.percentEncoded() print("URLRequest: \(request)") let task = URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data, let response = response as? HTTPURLResponse, error == nil else { // check for fundamental networking error print("error", error ?? URLError(.badServerResponse)) return } guard (200 ... 299) ~= response.statusCode else { // check for http errors print("statusCode should be 2xx, but is \(response.statusCode)") print("response = \(response)") return} do { let responseObject = try JSONDecoder().decode(ResponseObject<Foo>.self, from: data) print(responseObject) } catch { print(error) // parsing error if let responseString = String(data: data, encoding: .utf8) { print("responseString = \(responseString)") } else { print("unable to parse response as string") } } } task.resume() //executing the task } @IBAction func previbutton(_ sender: Any) { let vmc = storyboard?.instantiateViewController(withIdentifier: "second") as! SecondViewController vmc.modalPresentationStyle = .fullScreen present(vmc,animated:true) } }
config.php代码
<?php define('DB_USERNAME', 'root'); define('DB_PASSWORD', 'root'); define('DB_SERVER', 'localhost'); define('DB_NAME', 'emotion'); try{ $pdo = new PDO("mysql:host=" . DB_SERVER . ";dbname=" . DB_NAME, DB_USERNAME, DB_PASSWORD); // Set the PDO error mode to exception $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch(PDOException $e){ die("ERROR: Could not connect. " . $e->getMessage()); } ?>
insert.php代码
<?php // set up the response array $response = array(); // check if the request method is POST if ($_SERVER['REQUEST_METHOD'] == 'POST') { // get the userid from the POST request $userid = $_POST['userid']; // connect to the database require_once "config.php"; // insert the record into the database $sql = "INSERT INTO data (userid) VALUES (:userid)"; $stmt = $pdo->prepare($sql); $stmt->bindParam(':userid', $userid); $stmt->execute(); // set the success message in the response array $response['error'] = false; $response['message'] = 'Record inserted successfully'; } else { // set the error message in the response array $response['error'] = true; $response['message'] = 'You are not authorized'; } // return the response as JSON echo json_encode($response); // close the database connection unset($pdo); ?>
排查及解决方法
1. 查看PHP服务器错误日志
HTTP 500是服务器内部错误,优先查看服务器的PHP错误日志(比如MAMP的日志路径为/Applications/MAMP/logs/php_error.log),日志会明确指出错误原因,比如变量未定义、数据库操作异常等。
2. 修复Swift端参数空值问题
textg.text可能为nil,导致传递给PHP的userid参数不存在,触发服务器错误。修改Swift提交代码:
@IBAction func Submit(_ sender: Any) { guard let userId = textg.text, !userId.isEmpty else { print("User ID不能为空") return } let url = Foundation.URL(string: "http://ashok.local:8888/insert.php")! var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Accept") let parameters: [String: String] = [ "userid": userId ] request.httpBody = parameters.percentEncoded() let task = URLSession.shared.dataTask(with: request) { data, response, error in // 原有逻辑保留,仅修改参数部分 } task.resume() }
3. 给PHP数据库操作添加异常捕获
当前insert.php中数据库操作未做异常处理,若插入时出现约束错误(比如userid为空或不符合字段要求),会直接抛出错误导致500。修改insert.php:
if ($_SERVER['REQUEST_METHOD'] == 'POST') { // 先判断userid是否存在 if (!isset($_POST['userid']) || empty($_POST['userid'])) { $response['error'] = true; $response['message'] = 'User ID不能为空'; echo json_encode($response); exit; } $userid = $_POST['userid']; require_once "config.php"; try { $sql = "INSERT INTO data (userid) VALUES (:userid)"; $stmt = $pdo->prepare($sql); $stmt->bindParam(':userid', $userid); $stmt->execute(); $response['error'] = false; $response['message'] = 'Record inserted successfully'; } catch(PDOException $e) { $response['error'] = true; $response['message'] = '插入失败: ' . $e->getMessage(); } }
4. 修正Swift端响应解析模型
Swift中当前解析的ResponseObject<Foo>与PHP返回的JSON结构不匹配,会导致解析失败,需调整模型:
struct APIResponse: Decodable { let error: Bool let message: String } // 在dataTask的回调中替换解析逻辑 do { let responseObject = try JSONDecoder().decode(APIResponse.self, from: data) print(responseObject.message) } catch { // 原有错误处理保留 }
5. 检查iOS ATS设置
若服务器使用HTTP协议,需在Info.plist中添加ATS配置允许非HTTPS请求:
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
内容的提问来源于stack exchange,提问作者Bread
相关产品推荐
相关产品推荐

