提问人:mahen3d 提问时间:9/25/2021 更新时间:9/25/2021 访问量:287
SWIFT - JSON 错误 NSCocoaErrorDomain Code=3840“末尾垃圾”。
SWIFT - JSON Error NSCocoaErrorDomain Code=3840 "Garbage at end."
问:
我有以下函数,我尝试解码(base64),解密和创建JSON字典,
但是,由于某种未知原因,我收到一个名为 NSCocoaErrorDomain Code=3840 “Garbage at end.” 的错误,解密会在 JSON 字符串的末尾创建 \0\0\0\0\0\0\0(可能是填充)。我正在使用 CryptoSwift 来解密响应。我无法找到一种方法来使它工作,这应该非常简单,但我在代码中缺少一些重要的步骤。
import CryptoSwift
func orientation() -> Observable<AnyObject?> {
return Observable<AnyObject?>.create({ (observer) -> Disposable in
let request = Alamofire.Session.default.request(ResourcePath.Orientation.path+"2", method: .get, parameters: nil, encoding: JSONEncoding.default, headers: ["x-remote-origin":"ios"]).responseJSON(completionHandler: { (dataResponse) in
switch (dataResponse.result) {
case .success(let value) :
print(value)
do {
let json = JSON(value)
if let response = json.dictionary {
//Now you got your value
let result = response["response"]?.string;
let iv="something".bytes;
/* AES cryptor instance */
let aes = try AES(key: self.keyForCrypting, blockMode: CBC(iv: iv))
let encryptedData = Data(base64Encoded:result!)!
let decryptedData = Data(try aes.decrypt(encryptedData.bytes))
print(decryptedData);
let decryptedText = String(data: decryptedData, encoding: .utf8)
print(decryptedText);
let jsonData = try JSON(data: decryptedData)
print(jsonData);
}
}
catch {
print(error);
observer.onError(error)
return
}
break
case .failure(let error) :
observer.onError(error)
break
}
})
return Disposables.create {
request.cancel()
}
})
}
我的 JSON 输出 ( print(decryptedText); ) 在下面。
{\"oriens\":[{\"id\":\"1\",\"title\":\"Im Groom seeking a Bride\",\"search\":\"1\",\"gender\":\"M\",\"free\":\"N\",\"container\":{},\"dirtyState\":0,\"dirtyRelated\":[],\"errorMessages\":[],\"modelsManager\":{},\"modelsMetaData\":null,\"related\":[],\"operationMade\":0,\"oldSnapshot\":[],\"skipped\":null,\"snapshot\":null,\"transaction\":null,\"uniqueKey\":null,\"uniqueParams\":null,\"uniqueTypes\":null},{\"id\":\"2\",\"title\":\"Im Bride seeking a Groom\",\"search\":\"2\",\"gender\":\"F\",\"free\":\"Y\",\"container\":{},\"dirtyState\":0,\"dirtyRelated\":[],\"errorMessages\":[],\"modelsManager\":{},\"modelsMetaData\":null,\"related\":[],\"operationMade\":0,\"oldSnapshot\":[],\"skipped\":null,\"snapshot\":null,\"transaction\":null,\"uniqueKey\":null,\"uniqueParams\":null,\"uniqueTypes\":null},{\"id\":\"3\",\"title\":\"Im Boy seeking a Girl\",\"search\":\"3\",\"gender\":\"M\",\"free\":\"N\",\"container\":{},\"dirtyState\":0,\"dirtyRelated\":[],\"errorMessages\":[],\"modelsManager\":{},\"modelsMetaData\":null,\"related\":[],\"operationMade\":0,\"oldSnapshot\":[],\"skipped\":null,\"snapshot\":null,\"transaction\":null,\"uniqueKey\":null,\"uniqueParams\":null,\"uniqueTypes\":null},{\"id\":\"4\",\"title\":\"Im Girl seeking a Boy\",\"search\":\"4\",\"gender\":\"F\",\"free\":\"Y\",\"container\":{},\"dirtyState\":0,\"dirtyRelated\":[],\"errorMessages\":[],\"modelsManager\":{},\"modelsMetaData\":null,\"related\":[],\"operationMade\":0,\"oldSnapshot\":[],\"skipped\":null,\"snapshot\":null,\"transaction\":null,\"uniqueKey\":null,\"uniqueParams\":null,\"uniqueTypes\":null}]}\0\0\0\0\0\0
我的 XCode 输出是
答:
1赞
Cristik
9/25/2021
#1
下面是一个简短的扩展,用于删除尾随零:Data
extension Data {
func removingTrailingZeros() -> Data {
guard !isEmpty else { return self }
var lastValidIndex = index(before: endIndex)
while self[lastValidIndex] == 0 { lastValidIndex = index(before: lastValidIndex)}
return self[startIndex...lastValidIndex]
}
}
,则在代码中可以将其用作 .decryptedData.removingTrailingZeros()
请注意,它实际上并没有删除零,它所做的是创建一个新的,它投影到源字节的字节上,但只投影第一个零之前的字节(或者直到最后,如果没有尾随零)。removingTrailingZeros()
Data
0赞
mahen3d
9/25/2021
#2
我能够以某种方式让它以最奇怪的方式之一工作,当然有更好的方法可以做到这一点,只是在这里发布,以防有人可以添加更好更正确的代码来解决这个问题作为答案。
func orientation() -> Observable<AnyObject?> {
return Observable<AnyObject?>.create({ (observer) -> Disposable in
let request = Alamofire.Session.default.request(ResourcePath.Orientation.path+"2", method: .get, parameters: nil, encoding: JSONEncoding.default, headers: ["x-remote-origin":"ios"]).responseJSON(completionHandler: { (dataResponse) in
switch (dataResponse.result) {
case .success(let value) :
do {
let json = JSON(value)
if let response = json.dictionary {
let result = response["response"]?.string;
/* AES cryptor instance */
let aes = try AES(key: self.keyForCrypting, blockMode: CBC(iv: self.ivForCrypting.bytes), padding: .pkcs7)
let encryptedData = Data(base64Encoded:result!)!
let decryptedData = Data(try aes.decrypt(encryptedData.bytes))
let decryptedText = String(data: decryptedData, encoding: .utf8)
let reply = decryptedText?.replacingOccurrences(of: "\0", with:"");
let jsonData = try JSON(reply)
observer.onNext(jsonData.rawString()!.convertToDictionary() as AnyObject)
observer.onCompleted();
}
}
catch {
print(error);
observer.onError(error)
return
}
break
case .failure(let error) :
observer.onError(error)
break
}
})
return Disposables.create {
request.cancel()
}
})
}
评论
0赞
Cristik
9/26/2021
这里有一个更简洁的方法:stackoverflow.com/a/69325031/1974224 ;)
-1赞
gnasher729
9/25/2021
#3
你的代码看起来很奇怪。通常的顺序是:原始数据(例如JSON)+加密+base-64编码+传输+base-64解码+解密->原始数据(例如JSON)。
加密将添加一些填充,只要您对两者使用相同的参数,解密就会自动删除这些填充。但是,您有一个 base-64 编码步骤,在这一点上是完全奇怪的。
你可以把所有的处理都放到一个单独的函数中。
评论