Onfido沙箱创建Check时Swift请求报422错误求助
我帮你分析下这个问题——这种Python/curl能正常调用,但iOS Swift代码返回422 Unprocessable Entity的情况,基本都是请求格式、参数编码或者HTTP头的细节差异触发了Onfido的API验证规则。咱们结合代码对比来排查和解决:
核心差异点排查
首先对比你的Python和Swift代码,重点看这几个地方:
1. 确认Content-Type请求头是否正确
Onfido的API要求请求体必须是application/json格式,Python的requests.post(url, json=payload)会自动帮你设置这个头,但Swift的URLSession不会默认设置,如果你漏加或者设置错了格式(比如写成application/x-www-form-urlencoded),服务器会把你的JSON请求体当成表单数据解析,直接触发参数验证失败。
正确的Swift设置方式:
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
2. 检查JSON序列化的正确性
Swift中用JSONSerialization序列化字典时,要确保你的payload是合法的JSON类型:
- 数组必须是
[Any]类型(比如report_names必须是["identity"]而不是字符串"identity") - 不要包含JSON不支持的类型(比如自定义对象、nil,要用
NSNull代替nil)
另外,建议捕获序列化错误,避免请求体为空或格式错误:
do { request.httpBody = try JSONSerialization.data(withJSONObject: payload, options: []) } catch { print("JSON序列化失败:\(error.localizedDescription)") return }
3. 对比实际发送的请求体
用抓包工具(比如Charles、Proxyman)分别捕获Python和Swift的请求,对比两者的请求体内容:
- 检查参数名是否拼写正确(比如
applicant_id不要写成applicantId) - 检查数组格式是否正确(比如
report_names是不是数组,而不是单个字符串) - 检查是否有遗漏必填参数(Onfido创建Check必须有
applicant_id和至少一个report_names)
4. 验证Authorization头格式
确保Swift代码中的授权头格式和Python一致:Token token=你的沙箱API密钥,注意空格和大小写,不要写成Bearer或者其他格式。
修正后的完整Swift代码示例
import Foundation func createOnfidoCheck() { guard let apiUrl = URL(string: "https://api.sandbox.onfido.com/v3.3/checks") else { print("无效的API地址") return } var request = URLRequest(url: apiUrl) request.httpMethod = "POST" // 设置正确的HTTP头 request.setValue("Token token=你的沙箱API密钥", forHTTPHeaderField: "Authorization") request.setValue("application/json", forHTTPHeaderField: "Content-Type") // 构造符合要求的请求参数 let requestPayload: [String: Any] = [ "applicant_id": "你的申请人ID", "report_names": ["identity"] // 必须是数组类型,不能是单个字符串 ] // 序列化JSON并设置请求体 do { request.httpBody = try JSONSerialization.data(withJSONObject: requestPayload, options: []) } catch { print("JSON序列化出错:\(error.localizedDescription)") return } // 发送请求并处理响应 let task = URLSession.shared.dataTask(with: request) { data, response, error in if let error = error { print("请求出错:\(error.localizedDescription)") return } guard let httpResponse = response as? HTTPURLResponse else { print("未收到HTTP响应") return } print("响应状态码:\(httpResponse.statusCode)") if let responseData = data { do { let responseJson = try JSONSerialization.jsonObject(with: responseData, options: .allowFragments) print("响应内容:\(responseJson)") } catch { print("解析响应JSON失败:\(error.localizedDescription)") print("原始响应内容:\(String(data: responseData, encoding: .utf8) ?? "无原始数据")") } } } task.resume() } // 调用创建Check的函数 createOnfidoCheck()
额外调试技巧
如果还是报错,直接打印Onfido返回的错误详情(就是代码里的原始响应内容),里面会明确告诉你哪个参数不符合要求,比如"errors": [{"field": "report_names", "message": "must be an array"}],根据提示直接修正即可。
内容的提问来源于stack exchange,提问作者L.L

