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

Postman GET请求成功,SwiftUI App GET请求出现解码错误求助

Vapor接口SwiftUI解码错误排查

问题概述

运行Vapor服务器时,getOrders接口在Postman中调用正常,但SwiftUI App调用时触发JSON解码错误,其他接口均工作正常。

错误信息

typeMismatch(Swift.Double, Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "dateOrdered", intValue: nil)], debugDescription: "Expected to decode Double but found a string instead.", underlyingError: nil))

相关代码

1. SwiftUI应用端网络请求代码

func getOrders() async throws -> [Order] {
        
    let session = URLSession.shared
    var request = URLRequest(url: URL(string: "\(API.url)/orders/")!)
    
    request.httpMethod = "GET"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.setValue("Bearer \(token!.value)", forHTTPHeaderField: "Authorization")
        
    // 发起请求
    let (data, response) = try await session.data(for: request)
    print(data)
    
    print(response)
    // 验证响应状态码
    guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
        throw GetOrdersError.unableToGetOrders
    }
    print(httpResponse.statusCode)
        
    let decoder = JSONDecoder()
    let orders = try decoder.decode([Order].self, from: data)
    
    print(orders)
    return orders
}

2. SwiftUI应用端Order模型

struct Order: Identifiable, Codable {
    
    var id: UUID?
    var residentID: UUID
    var house: String
    var dateOrdered: Date
    var allPurposeCleaner: Bool
    var airFreshener: Bool
    var laundryPods: Bool
    var dishPods: Bool
    var dishSoap: Bool
    var windex: Bool
    var cloroxWipes: Bool
    var paperTowels: Bool
    var toiletPaper: Bool
    var toiletBowlCleaner: Bool
    var thrift: Bool
    var swifferPads: Bool
    var trashBags: Bool
    var isOrderCompleted: Bool
    
    static let houses = ["Wolf Pack", "Crow House", "Raptor House", "Lemur House", "Orca Pod", "Gorilla House", "Bison House", "Lion's Den"]
    
    init(id: UUID?, residentID: UUID, house: String, dateOrdered: Date, allPurposeCleaner: Bool, airFreshener: Bool, laundryPods: Bool, dishPods: Bool, dishSoap: Bool, windex: Bool, cloroxWipes: Bool, paperTowels: Bool, toiletPaper: Bool, toiletBowlCleaner: Bool, thrift: Bool, swifferPads: Bool, trashBags: Bool, isOrderCompleted: Bool) {
        self.id = id
        self.residentID = residentID
        self.house = house
        self.dateOrdered = dateOrdered
        self.allPurposeCleaner = allPurposeCleaner
        self.airFreshener = airFreshener
        self.laundryPods = laundryPods
        self.dishPods = dishPods
        self.dishSoap = dishSoap
        self.windex = windex
        self.cloroxWipes = cloroxWipes
        self.paperTowels = paperTowels
        self.toiletPaper = toiletPaper
        self.toiletBowlCleaner = toiletBowlCleaner
        self.thrift = thrift
        self.swifferPads = swifferPads
        self.trashBags = trashBags
        self.isOrderCompleted = isOrderCompleted
    }
}

3. Vapor服务器端Order模型

import Foundation
import Vapor
import Fluent

final class Order: Model, Content {
    
    init() {
    }
    
    static var schema: String = "orders"
    
    init(id: UUID, residentID: UUID, house: String, dateOrdered: Date, allPurposeCleaner: Bool, airFreshener: Bool, laundryPods: Bool, dishPods: Bool, dishSoap: Bool, windex: Bool, cloroxWipes: Bool, paperTowels: Bool, toiletPaper: Bool, toiletBowlCleaner: Bool, thrift: Bool, swifferPads: Bool, trashBags: Bool, isOrderCompleted: Bool) {
        self.id = id
        self.residentID = residentID
        self.house = house
        self.dateOrdered = dateOrdered
        self.allPurposeCleaner = allPurposeCleaner
        self.airFreshener = airFreshener
        self.laundryPods = laundryPods
        self.dishPods = dishPods
        self.dishSoap = dishSoap
        self.windex = windex
        self.cloroxWipes = cloroxWipes
        self.paperTowels = paperTowels
        self.toiletPaper = toiletPaper
        self.toiletBowlCleaner = toiletBowlCleaner
        self.thrift = thrift
        self.swifferPads = swifferPads
        self.trashBags = trashBags
        self.isOrderCompleted = isOrderCompleted
    }
    
    @ID(key: .id)
    var id: UUID?
    
    @Field(key: "residentID")
    var residentID: UUID
    
    @Field(key: "house")
    var house: String
    
    @Field(key: "dateOrdered")
    var dateOrdered: Date
    
    @Field(key: "allPurposeCleaner")
    var allPurposeCleaner: Bool
    
    @Field(key: "airFreshener")
    var airFreshener: Bool
    
    @Field(key: "laundryPods")
    var laundryPods: Bool
    
    @Field(key: "dishPods")
    var dishPods: Bool
    
    @Field(key: "dishSoap")
    var dishSoap: Bool
    
    @Field(key: "windex")
    var windex: Bool
    
    @Field(key: "cloroxWipes")
    var cloroxWipes: Bool
    
    @Field(key: "paperTowels")
    var paperTowels: Bool
    
    @Field(key: "toiletPaper")
    var toiletPaper: Bool
    
    @Field(key: "toiletBowlCleaner")
    var toiletBowlCleaner: Bool
    
    @Field(key: "thrift")
    var thrift: Bool
    
    @Field(key: "swifferPads")
    var swifferPads: Bool
    
    @Field(key: "trashBags")
    var trashBags: Bool
    
    @Field(key: "isOrderCompleted")
    var isOrderCompleted: Bool
    
}

Postman请求验证

Postman请求成功截图

解决方案

错误核心是dateOrdered字段的格式不匹配:Vapor默认将Date序列化为ISO8601字符串,而Swift的JSONDecoder默认期望时间戳(Double类型),导致解码失败。

修复步骤:

  1. 在SwiftUI应用端配置JSONDecoder日期解码策略
    修改网络请求代码中的JSONDecoder初始化部分,指定使用ISO8601格式解码日期:

    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .iso8601 // 添加该行
    let orders = try decoder.decode([Order].self, from: data)
    
  2. 可选:统一服务器端日期序列化格式
    若要确保Vapor输出的日期格式一致,可在服务器端configure.swift中配置ContentConfiguration:

    let contentConfig = ContentConfiguration.default()
    let jsonEncoder = JSONEncoder()
    jsonEncoder.dateEncodingStrategy = .iso8601
    contentConfig.use(encoder: jsonEncoder, for: .json)
    app.content = contentConfig
    

验证

修改后重新运行SwiftUI App,调用getOrders接口即可正常解码dateOrdered字段。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 01:17:03