SwiftUI WikiVoyage API数据模型JSON解析失败求助
SwiftUI WikiVoyage API JSON解析invalidData错误排查
已成功发起WikiVoyage API网络请求,但解析返回JSON时触发invalidData错误,目标是获取extract字段中的HTML字符串。
Proxyman捕获的响应体
{ "batchcomplete": true, "warnings": { "extracts": { "warnings": "HTML may be malformed and/or unbalanced and may omit inline images. Use at your own risk. Known problems are listed at https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TextExtracts#Caveats." } }, "query": { "pages": [ { "pageid": 5125, "ns": 0, "title": "Buriram", "index": 1, "thumbnail": { "source": "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Train_Time_Table_at_Buriram_Station..jpg/250px-Train_Time_Table_at_Buriram_Station..jpg", "width": 250, "height": 188 }, "extract": "HTML string here" } ] } }
数据模型代码
import Foundation struct WikiVoyageResponse: Codable { let query: Query } struct Query: Codable { let pages: [Page] } struct Page: Codable { let pageid: Int let ns: Int let title: String let index: Int let thumbnail: Thumbnail let extract: String } struct Thumbnail: Codable { let source: String let width: Int let height: Int }
API调用代码
func getWikiData() async throws -> String { // 浏览器中可正常获取数据 let urlString = "https://en.wikivoyage.org/w/api.php?origin=*&action=query&format=json&prop=pageimages%7Cextracts&exlimit=1&generator=prefixsearch&redirects=1&formatversion=2&piprop=thumbnail&pithumbsize=250&pilimit=20&gpssearch=Buriram&gpslimit=1" guard let url = URL(string: urlString) else { throw DataError.invalidURL // 通知用户 } let (data, response) = try await URLSession.shared.data(from: url) guard let response = response as? HTTPURLResponse, response.statusCode == 200 else { throw DataError.invalidResponse // 通知用户 } do { let decoder = JSONDecoder() let response = try decoder.decode(WikiVoyageResponse.self, from: data) // 期望获取extract中的HTML字符串,但触发invalidData错误 print("Response", response.query.pages[0].extract) return response.query.pages[0].extract } catch { throw DataError.invalidData } }
问题排查与解决方案
1. 模型未处理响应中的额外字段
响应包含batchcomplete和warnings字段,但当前模型未定义这些字段,JSONDecoder默认会因存在未知字段抛出错误。解决方式二选一:
- 添加可选字段:扩展模型结构,将额外字段标记为可选
struct WikiVoyageResponse: Codable { let query: Query let batchcomplete: Bool? let warnings: Warnings? } struct Warnings: Codable { let extracts: ExtractWarning? } struct ExtractWarning: Codable { let warnings: String? } - 配置解码器忽略未知字段:修改解码器设置,跳过模型中未定义的字段
let decoder = JSONDecoder() decoder.ignoresUnknownKeys = true // 关键设置 let response = try decoder.decode(WikiVoyageResponse.self, from: data)
2. 非可选字段可能为nil
部分场景下API可能不返回thumbnail字段,当前模型中thumbnail为非可选类型,会导致解析失败,建议改为可选:
struct Page: Codable { let pageid: Int let ns: Int let title: String let index: Int let thumbnail: Thumbnail? // 改为可选 let extract: String }
3. 检查原始JSON格式
若上述调整后仍报错,可打印原始响应字符串,排查是否存在转义错误或格式问题:
if let rawJson = String(data: data, encoding: .utf8) { print("原始响应字符串:\(rawJson)") }
内容的提问来源于stack exchange,提问作者Mike Haslam
相关产品推荐
相关产品推荐

