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

如何在Swift应用中反序列化AWS API Gateway+Lambda的响应?

AWS Lambda + API Gateway 集成后Swift请求JSON解码失败问题

问题详情

Lambda函数代码

def lambda_handler(event, context):
    # Logic
    return json.dumps({"name": "foo", "job": "bar"})

curl请求结果

通过API Gateway端点请求时,返回带转义的字符串形式JSON:

$ curl https://my-aws-gateway-endpoint/stage/endpoint

"{\"name\": \"foo\", \"job\": \"bar\"}"

Swift请求错误

Swift应用发起请求时抛出解码错误:

typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary<String, Any> but found a string/data instead.", underlyingError: nil))

Swift请求代码

let semaphore = DispatchSemaphore(value: 0)
var data: Data // This is a struct that contains the fields "name" and "job"
let task = URLSession.shared.dataTask(with: url) { data, response, error in
            defer { semaphore.signal() }

            if let _ = error {
                return
            }

            guard let httpResponse = response as? HTTPURLResponse,
                  (200...299).contains(httpResponse.statusCode) else {
                print("Invalid response: \(response?.description ?? \"")")
                return
            }

            guard let data = data else {
                print("No data received")
                return
            }

            do {
                let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
                let jsonData = try JSONSerialization.data(withJSONObject: json, options: .fragmentsAllowed)
                let decoder = JSONDecoder()
                songData = try decoder.decode(Data.self, from: jsonData)
            } catch {
                print(error)
                return
            }
}

task.resume()
semaphore.wait()

return data

错误原因

  1. Lambda返回格式错误:手动用json.dumps()将字典转为字符串后,API Gateway会把该字符串当作普通数据包装成JSON响应,最终客户端拿到的是包含JSON字符串的JSON值,而非直接的JSON对象。
  2. Swift解码逻辑错误:代码先将响应数据解析为JSON对象(实际是字符串),再转回Data后用JSONDecoder解码结构体。此时解码器拿到的是字符串数据,而非预期的字典结构,触发类型不匹配错误。此外,结构体命名Data与Swift系统Data类重名,会导致语法混淆。

解决方案

方案1:修正Lambda代码(推荐,规范做法)

Lambda无需手动序列化JSON,直接返回Python字典即可。API Gateway会自动将其序列化为正确的JSON对象,并设置Content-Type: application/json响应头:

def lambda_handler(event, context):
    # Logic
    return {"name": "foo", "job": "bar"}

方案2:修正Swift代码(临时兼容方案)

若无法修改Lambda,可在Swift端先解析外层字符串,再转为Data后解码,同时修改结构体名称避免冲突:

// 重命名结构体,避免与系统Data类冲突
struct UserData: Codable {
    let name: String
    let job: String
}

let semaphore = DispatchSemaphore(value: 0)
var songData: UserData?

let task = URLSession.shared.dataTask(with: url) { data, response, error in
    defer { semaphore.signal() }
    
    if let error = error {
        print(error)
        return
    }
    
    guard let httpResponse = response as? HTTPURLResponse,
          (200...299).contains(httpResponse.statusCode) else {
        print("Invalid response: \(response?.description ?? "")")
        return
    }
    
    guard let data = data else {
        print("No data received")
        return
    }
    
    do {
        // 解析外层的JSON字符串
        guard let jsonString = try JSONSerialization.jsonObject(with: data) as? String else {
            print("Failed to extract JSON string")
            return
        }
        // 将字符串转为Data
        guard let innerData = jsonString.data(using: .utf8) else {
            print("Failed to convert string to data")
            return
        }
        // 解码为结构体
        let decoder = JSONDecoder()
        songData = try decoder.decode(UserData.self, from: innerData)
    } catch {
        print(error)
        return
    }
}

task.resume()
semaphore.wait()

return songData

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 03:14:58