Swift中URLSession.dataTask返回的Error与HTTP状态码的区别及结果正确解析方式
Swift中URLSession.dataTask返回的Error与HTTP状态码的区别及结果正确解析方式
我完全理解你的困惑——刚用URLSession的时候很容易把error和HTTP状态码混为一谈,我当初也踩过这个坑!咱们先把核心区别讲清楚,再给你梳理正确的解析流程和优化后的代码。
一、Error与HTTP状态码的核心区别
error参数的意义:这个error只表示客户端侧的请求发送失败,比如:- 网络断开,根本连不上服务器
- 域名解析失败(比如把域名写错了)
- 请求被系统安全策略拦截(比如ATS限制)
- 服务器完全没有返回任何响应(比如超时)
只要服务器成功接收到你的请求,并且返回了任何响应(哪怕是500、404这种错误响应),error就会是nil。
HTTP状态码的意义:状态码是服务器返回的业务/服务端错误标识,比如:
- 200/201:请求成功
- 4xx:客户端请求有误(比如401未授权、404资源不存在)
- 5xx:服务器内部错误(比如你遇到的500,通常是服务器代码bug、数据库连接失败等)
这些情况都属于“请求已经成功发送并得到响应”,所以error不会被触发。
你提到的服务器配置问题:500状态码返回HTML而不是标准错误JSON,这确实是服务器端的处理不规范(正常来说500应该返回结构化的错误信息),但作为客户端,我们还是要兼容这种情况。
二、正确的dataTask结果解析流程
正确的处理顺序应该是:先判断客户端错误→再验证HTTP状态码→最后处理响应数据,这样逻辑更清晰,也不会出现混乱。
优化后的代码如下:
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in // 1. 优先处理客户端层面的错误 if let error = error { print("客户端请求错误:\(error.localizedDescription)") return // 客户端错误直接终止后续处理 } // 2. 验证响应是否为HTTP响应,并检查状态码 guard let httpResponse = response as? HTTPURLResponse else { print("非HTTP响应,处理失败") return } // 3. 根据状态码分支处理 switch httpResponse.statusCode { case 200...299: // 成功状态码范围 guard let data = data else { print("成功响应但无数据") return } // 解析JSON do { guard let jsonResults = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { print("JSON解析失败,数据格式不符合预期") return } // 解析业务数据 if let responseDict = jsonResults["response"] as? [String: Any], let message = responseDict["message"] as? String { print("业务返回消息:\(message)") } } catch { print("JSON解析出错:\(error.localizedDescription)") } case 400...499: // 客户端错误状态码 print("客户端请求错误,状态码:\(httpResponse.statusCode)") // 可以根据需要解析4xx的错误数据(比如服务器返回的错误提示) if let data = data { let errorText = String(data: data, encoding: .utf8) print("服务器返回的错误信息:\(errorText ?? "无文本数据")") } case 500...599: // 服务器错误状态码 print("服务器内部错误,状态码:\(httpResponse.statusCode)") // 你遇到的500返回HTML的情况,就在这里处理 if let data = data { let errorHtml = String(data: data, encoding: .utf8) print("服务器返回的错误页面:\(errorHtml ?? "无HTML数据")") } default: // 其他状态码 print("未知状态码:\(httpResponse.statusCode)") } } task.resume()
三、代码优化的关键点说明
- 顺序优先:先处理
error,再处理响应状态码,最后处理数据——符合请求失败的优先级逻辑。 - 状态码范围判断:用
200...299代替硬写200,因为201、204等也属于成功状态码,更严谨。 - 用do-catch替代try?:
try?会吞掉解析错误,用do-catch可以明确捕获JSON解析失败的原因,方便调试。 - 可选绑定的安全处理:避免强制解包(比如你原代码中的
responsestr!),用guard和可选链更安全,不会触发崩溃。 - 分支清晰:按状态码范围分支处理,不同类型的错误逻辑分开,可读性更强。
如果服务器的500响应有时候返回JSON有时候返回HTML,你可以在5xx的分支里先尝试解析JSON,如果失败再转成字符串处理,这样兼容性更好。
内容来源于stack exchange
相关产品推荐
相关产品推荐

