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

Swift中使用Alamofire调用WebService无法获取有效JSON求助

问题排查与解决方案

从你给出的错误信息和代码来看,主要有两个核心问题导致请求失败:URL路径错误和请求参数编码方式不匹配,这也是为什么Postman能正常工作但Alamofire不行的原因。


1. 修复URL中的多余斜杠

你代码里的URL都存在多余的双斜杠:

  • 登录接口:http://192.169.201.32:9000//users/authenticate → 需改为http://192.169.201.32:9000/users/authenticate
  • 注册接口:http://192.169.201.32:9000//patient/signUp → 需改为http://192.169.201.32:9000/patient/signUp

多余的斜杠会导致服务器无法匹配正确的路由,直接返回404错误——这就是你看到error with response status: 404的原因。而服务器返回的404页面是HTML格式,并非JSON,所以Alamofire尝试解析JSON时就会抛出Invalid value around character 2的错误。

2. 改用JSON编码方式传递参数

你在Postman里用的是Body → raw → JSON格式提交参数,但代码里用的是URLEncoding.default——这个编码方式会把参数拼接到URL后或作为form表单提交,和服务器期望的JSON请求体完全不匹配。

需要把编码方式改成JSONEncoding.default,同时还要处理文本框的可选值(比如textField.text可能为nil,直接传递会导致JSON序列化失败)。

修复后的登录接口代码:

// 修正后的URL
let url = "http://192.169.201.32:9000/users/authenticate"

@IBAction func DoLogin(_ sender: AnyObject) {
    // 先处理登出逻辑,避免无效请求
    if login_button.titleLabel?.text == "Logout" {
        let preferences = UserDefaults.standard
        preferences.removeObject(forKey: "session")
        LoginToDo()
        return // 退出方法,不执行后续登录请求
    }
    
    // 校验输入框内容,处理可选值
    guard let username = username_input.text, !username.isEmpty,
          let password = password_input.text, !password.isEmpty else {
        print("请输入完整的用户名和密码")
        return
    }
    
    Alamofire.request(url, 
                      method: .post, 
                      parameters: ["username": username, "password": password], 
                      encoding: JSONEncoding.default) // 改用JSON编码
        .responseJSON { response in
            print("登录请求响应:")
            print(response)
            
            // 状态码判断
            if let status = response.response?.statusCode {
                switch status {
                case 200...299:
                    print("登录成功")
                case 401:
                    print("用户名或密码错误")
                default:
                    print("请求失败,状态码:\(status)")
                }
            }
            
            // 安全解析JSON
            switch response.result {
            case .success(let value):
                if let json = value as? [String: Any] {
                    print("登录返回JSON:\(json)")
                    // 这里可以处理token等业务逻辑
                }
            case .failure(let error):
                print("JSON解析失败:\(error.localizedDescription)")
            }
    }
}

修复后的注册接口代码:

// 修正后的URL
let url = "http://192.169.201.32:9000/patient/signUp"

@IBAction func signUpButtonWasPressed(_ sender: Any) {
    // 校验所有输入字段,处理可选值
    guard let dob = DateOfBirthTextFeild.text, !dob.isEmpty,
          let email = emailIdTextField.text, !email.isEmpty,
          let firstName = FirstNameTextField.text, !firstName.isEmpty,
          let gender = genderTextField.text, !gender.isEmpty,
          let lastName = LastNameTextField.text, !lastName.isEmpty,
          let password = passwordTextField.text, password.count >= 8,
          let ssn = ssnTextField.text, !ssn.isEmpty else {
        print("请完善所有必填信息,密码长度至少8位")
        return
    }
    
    let parameters: [String: Any] = [
        "dob": dob,
        "email": email,
        "firstName": firstName,
        "gender": gender,
        "lastName": lastName,
        "middleName": MiddleNameTextField.text ?? "", // 可选字段为空时传空字符串
        "password": password,
        "ssn": ssn
    ]
    
    Alamofire.request(url, 
                      method: .post, 
                      parameters: parameters, 
                      encoding: JSONEncoding.default) // 改用JSON编码
        .responseJSON { response in
            print("注册请求响应:")
            print(response)
            
            if let status = response.response?.statusCode {
                switch status {
                case 200...299:
                    print("注册成功")
                default:
                    print("请求失败,状态码:\(status)")
                }
            }
            
            // 安全解析JSON
            switch response.result {
            case .success(let value):
                if let json = value as? [String: Any] {
                    print("注册返回JSON:\(json)")
                }
            case .failure(let error):
                print("JSON解析失败:\(error.localizedDescription)")
            }
    }
}

额外优化建议

  • 把按钮的业务逻辑(登录/登出)放在请求之前,并添加return,避免执行不必要的请求。
  • 对输入内容做格式校验(比如邮箱格式、SSN格式),提前拦截无效输入。
  • 避免使用强制解包(比如as! NSDictionary),改用as? [String: Any]更安全,防止崩溃。
  • JSONEncoding.default会自动添加Content-Type: application/json请求头,无需手动设置。

按照上面的修改,你的请求应该就能和Postman一样正常获取JSON响应了。

内容的提问来源于stack exchange,提问作者aaaaaaaaaaaaaaaaaaaaaaaaa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:29:17