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

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()

三、代码优化的关键点说明

  1. 顺序优先:先处理error,再处理响应状态码,最后处理数据——符合请求失败的优先级逻辑。
  2. 状态码范围判断:用200...299代替硬写200,因为201、204等也属于成功状态码,更严谨。
  3. 用do-catch替代try?:try?会吞掉解析错误,用do-catch可以明确捕获JSON解析失败的原因,方便调试。
  4. 可选绑定的安全处理:避免强制解包(比如你原代码中的responsestr!),用guard和可选链更安全,不会触发崩溃。
  5. 分支清晰:按状态码范围分支处理,不同类型的错误逻辑分开,可读性更强。

如果服务器的500响应有时候返回JSON有时候返回HTML,你可以在5xx的分支里先尝试解析JSON,如果失败再转成字符串处理,这样兼容性更好。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 09:48:04