You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 08:10:38