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

SwiftUI中Alamofire请求API出现ResponseSerializationFailureReason错误

问题描述
  • 接口调用偶发成功、偶发失败,同一请求在Postman中可正常运行
  • 核心报错为响应序列化失败,提示传入数据不是合法JSON,第1行第0列位置存在无效值,使用responseDecodable解析[Category]模型数组失败

报错信息如下:

failure(Alamofire.AFError.responseSerializationFailed(reason: Alamofire.AFError.ResponseSerializationFailureReason.decodingFailed(error: Swift.DecodingError.dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around line 1, column 0." UserInfo={NSDebugDescription=Invalid value around line 1, column 0., NSJSONSerializationErrorIndex=0}))))))

原有业务实现代码:

class TemplateObserver: ObservableObject {
@Published var category = [Category]()

init(){
    fetchCategories()
}
func fetchCategories() {
    let request = AF.request(Constants.CATEGORIES, method: .get)
    request.responseDecodable(of: [Category].self) { response in
        print("Category Response: (response)")
        guard let result = response.value else { return }
        self.category = result
    }
  }
}

原有App初始化代码:

@main
struct Logo_MakerApp: App {
    @ObservedObject var templateObserver = TemplateObserver()

    var body: some Scene {
    WindowGroup {
        ContentView(
            templateObserver: templateObserver
        )
    }
  }
}
根因方向

报错指向响应起始位置(第1行第0列)就不符合JSON格式,常见触发场景:

  • 接口偶发返回非JSON内容:比如网关限流、鉴权失效、服务端节点异常时返回HTML格式的错误页,或者空响应体
  • 服务端返回的JSON带UTF-8 BOM头,前置3个特殊字节导致JSON解析器从起始位置就识别失败
  • 生命周期声明错误导致实例重复创建、重复发请求,触发请求时序异常
  • 未设置正确的Accept请求头,服务端偶发返回非JSON格式的响应
排查&修复方案
  1. 先打印原始响应内容
    原有代码直接在解码失败时return,没有输出原始返回数据,无法定位实际拿到的内容。先将responseDecodable替换为responseData拿到原始二进制数据,转成UTF-8字符串打印,90%的场景可以直接定位问题(比如看到返回内容是<html>开头的错误页,还是空字符串)。
  2. 修复通用问题
    • 给请求加上Accept: application/json请求头,明确告知服务端需要返回JSON格式
    • 增加UTF-8 BOM头过滤逻辑,兼容服务端不规范返回
    • 所有UI和数据赋值操作显式切到主线程,避免时序问题
    • 将App层级的@ObservedObject替换为@StateObject,保证ObservableObject实例生命周期正确,不会被系统意外重建重复发起请求

修复后的可直接运行代码:

class TemplateObserver: ObservableObject {
    @Published var category = [Category]()

    init(){
        fetchCategories()
    }
    
    func fetchCategories() {
        // 明确指定Accept请求头
        let headers: HTTPHeaders = [
            "Accept": "application/json"
        ]
        
        AF.request(Constants.CATEGORIES, method: .get, headers: headers)
            .responseData { [weak self] response in
                guard let self = self else { return }
                // 打印响应状态码,快速定位是否是HTTP错误
                print("接口响应状态码: \(response.response?.statusCode ?? -1)")
                
                switch response.result {
                case .success(var rawData):
                    // 过滤UTF-8 BOM头
                    let bomHeader: [UInt8] = [0xEF, 0xBB, 0xBF]
                    if rawData.count >= 3, Array(rawData.prefix(3)) == bomHeader {
                        rawData = rawData.dropFirst(3)
                    }
                    
                    // 打印原始响应字符串,排查非JSON内容
                    if let responseText = String(data: rawData, encoding: .utf8) {
                        print("原始响应内容: \(responseText)")
                    }
                    
                    // 手动解码
                    do {
                        let result = try JSONDecoder().decode([Category].self, from: rawData)
                        DispatchQueue.main.async {
                            self.category = result
                        }
                    } catch {
                        print("JSON解码失败: \(error)")
                    }
                    
                case .failure(let reqError):
                    print("网络请求失败: \(reqError)")
                }
            }
    }
}

修正后的App入口代码:

@main
struct Logo_MakerApp: App {
    // 自身持有的ObservableObject用@StateObject,保证生命周期正确
    @StateObject var templateObserver = TemplateObserver()

    var body: some Scene {
        WindowGroup {
            ContentView(templateObserver: templateObserver)
        }
    }
}
  1. 针对性排查
    如果加了日志后发现偶发场景下返回的是403/429/502等HTTP错误码、对应内容是HTML错误页,需要和后端同学确认网关限流、鉴权有效期、负载均衡节点异常的问题,这类问题Postman因为请求频率低、带的请求头和App端有差异,往往不会触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 12:31:02