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

Vapor中Date未序列化为ISO8601字符串问题排查

Vapor中Date字段未按ISO8601格式输出的问题解决

问题场景

我在使用Vapor开发Swift服务端应用,定义了如下传输对象模型:

protocol TransferObject: Content {}

protocol TimeAuditedTransferObject : TransferObject {
    
    var createdDate: Date { get }
    var lastUpdate: Date { get }
    
}
    
protocol IdentifiedTransferObject : TimeAuditedTransferObject {
    
    var uniqueIdentifier: String { get }
}


struct PageSummaryModel : IdentifiedTransferObject, Codable {
    
    let uniqueIdentifier: String
    
    let title: String
    let shortDescription: String?
    
    let owner: BaseUserProfileModel
    
    let createdDate: Date
    let lastUpdate: Date
    
    init(uniqueIdentifier: String,
         title: String,
         shortDescription: String? = nil,
         owner: BaseUserProfileModel,
         createdDate: Date,
         lastUpdate: Date) {
        self.uniqueIdentifier = uniqueIdentifier
        self.title = title
        self.shortDescription = shortDescription
        self.owner = owner
        self.createdDate = createdDate
        self.lastUpdate = lastUpdate
    }
}

返回该类型对象时,createdDate和lastUpdate以时间戳小数形式输出(示例如下),而非预期的ISO8601字符串:

{
   "owner":{
      "familyName":"FAMILY",
      "createdDate":765751685.181461,
      "uniqueIdentifier":"abcd1234",
      "givenName":"GIVEN",
      "lastUpdate":765751685.181461
   },
   "uniqueIdentifier":"01961214-4BAA-7A6C-972D-FD6DD1457B70",
   "createdDate":765752842.15402,
   "lastUpdate":765752842.15402,
   "title":"MyPage1234",
   "shortDescription":"My Short Description"
}

我已尝试根据Vapor文档配置全局JSON编码器,但输出仍无变化:

let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601

ContentConfiguration.global.use(encoder: encoder, for: .json)
ContentConfiguration.global.use(decoder: decoder, for: .json)

问题原因与解决方法

问题核心在于模型的协议遵循逻辑和配置时机:

1. 重复遵循Codable导致配置失效

Vapor的Content协议本身已经继承了Codable,你的PageSummaryModel同时声明遵循IdentifiedTransferObject(最终继承自Content)和Codable,会绕过Vapor的全局编码器配置,使用原生Codable的默认日期编码策略(即时间戳)。

2. 配置时机可能过晚

如果全局配置代码不是在应用启动初期执行,可能会被后续的默认配置覆盖。

具体修复步骤

  • 移除结构体的Codable声明:
struct PageSummaryModel : IdentifiedTransferObject {
    // 原结构体内容保持不变
}
  • 检查BaseUserProfileModel的协议遵循:确保它同样遵循Content相关协议(而非直接Codable),否则它的日期字段也会使用默认编码策略。
  • 调整配置代码位置:在configure.swift中优先配置全局编码器,放在路由、数据库等其他配置之前:
func configure(_ app: Application) throws {
    // 先配置全局编码器/解码器
    let encoder = JSONEncoder()
    encoder.dateEncodingStrategy = .iso8601
    
    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .iso8601
    
    ContentConfiguration.global.use(encoder: encoder, for: .json)
    ContentConfiguration.global.use(decoder: decoder, for: .json)
    
    // 后续的路由、服务配置
    try routes(app)
}

补充说明

如果上述修改后仍有问题,可检查是否有其他地方局部自定义了编码器,覆盖了全局配置。核心原则是让所有需要序列化的模型都通过Vapor的Content协议处理,确保全局配置的编码器生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 11:41:12