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
相关产品推荐
相关产品推荐

