从可解码模型解码 url 其中包含 space
Decode url with space in it from decodable model
我有以下结构并且响应解析失败,因为 url (https://example.url.com/test a
) 中有一个 space。如何在反序列化层中使用 %20 值对其进行转义并将其保持为 URL 类型?
struct Response: Decodable {
let url: URL
enum CodingKeys: String, CodingKey {
case url
}
init(from decoder: Decoder) throws {
self.url = try decoder.container(keyedBy: CodingKeys.self).decode(URL.self, forKey: .url)
}
}
let string = "{\"url\":\"https://example.url.com/test a\"}"
let responseModel = try? JSONDecoder().decode(Response.self, from: string.data(using: .utf8)!)
print(responseModel?.url)
我认为使用 JSONDecoder
自定义或序列化层是不可能的,正如您在 post 中提到的那样。你能做到的最好的就是这样做:
struct Response: Decodable {
let urlString: String
var url: URL {
URL(string: urlString.replacingOccurrences(of: " ", with: "%20"))!
}
enum CodingKeys: String, CodingKey {
case urlString = "url"
}
}
注意:如果您没有自定义实现,则不需要 init(decoder:)
。如果 属性 名称与字符串键相同(在您的情况下 url
键是多余的),也不需要 CodingKeys
枚举。
您不能将 url
解码为 URL,如 decode(URL.self...
),因为它 不是 URL .将你的 url
属性 更改为 String,将此值解码为 String.self
,并处理将 String 转换为 URL 之后的 过程。
正如 Rob 已经提到的,最好在后端解决问题而不是修复解码部分。如果你不能在服务器端修复它,你可以将你的 url 解码为一个字符串,百分比转义它然后使用结果字符串来初始化你的 url 属性:
struct Response: Codable {
let url: URL
}
extension Response {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let string = try container.decode(String.self, forKey: .url)
guard
let percentEncoded = string
.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let url = URL(string: percentEncoded)
else {
throw DecodingError.dataCorruptedError(forKey: .url,
in: container,
debugDescription: "Invalid url string: \(string)")
}
self.url = url
}
}
游乐场测试
let jsonString = #"{"url":"https://example.url.com/test a"}"#
do {
let responseModel = try JSONDecoder().decode(Response.self, from: Data(jsonString.utf8))
print(responseModel.url)
} catch { print(error) }
这将打印
我有以下结构并且响应解析失败,因为 url (https://example.url.com/test a
) 中有一个 space。如何在反序列化层中使用 %20 值对其进行转义并将其保持为 URL 类型?
struct Response: Decodable {
let url: URL
enum CodingKeys: String, CodingKey {
case url
}
init(from decoder: Decoder) throws {
self.url = try decoder.container(keyedBy: CodingKeys.self).decode(URL.self, forKey: .url)
}
}
let string = "{\"url\":\"https://example.url.com/test a\"}"
let responseModel = try? JSONDecoder().decode(Response.self, from: string.data(using: .utf8)!)
print(responseModel?.url)
我认为使用 JSONDecoder
自定义或序列化层是不可能的,正如您在 post 中提到的那样。你能做到的最好的就是这样做:
struct Response: Decodable {
let urlString: String
var url: URL {
URL(string: urlString.replacingOccurrences(of: " ", with: "%20"))!
}
enum CodingKeys: String, CodingKey {
case urlString = "url"
}
}
注意:如果您没有自定义实现,则不需要 init(decoder:)
。如果 属性 名称与字符串键相同(在您的情况下 url
键是多余的),也不需要 CodingKeys
枚举。
您不能将 url
解码为 URL,如 decode(URL.self...
),因为它 不是 URL .将你的 url
属性 更改为 String,将此值解码为 String.self
,并处理将 String 转换为 URL 之后的 过程。
正如 Rob 已经提到的,最好在后端解决问题而不是修复解码部分。如果你不能在服务器端修复它,你可以将你的 url 解码为一个字符串,百分比转义它然后使用结果字符串来初始化你的 url 属性:
struct Response: Codable {
let url: URL
}
extension Response {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let string = try container.decode(String.self, forKey: .url)
guard
let percentEncoded = string
.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let url = URL(string: percentEncoded)
else {
throw DecodingError.dataCorruptedError(forKey: .url,
in: container,
debugDescription: "Invalid url string: \(string)")
}
self.url = url
}
}
游乐场测试
let jsonString = #"{"url":"https://example.url.com/test a"}"#
do {
let responseModel = try JSONDecoder().decode(Response.self, from: Data(jsonString.utf8))
print(responseModel.url)
} catch { print(error) }
这将打印