SWIFT - JSON 错误 NSCocoaErrorDomain Code=3840 "Garbage at end."
SWIFT - JSON Error NSCocoaErrorDomain Code=3840 "Garbage at end."
我有以下功能,我尝试解码(base64)、解密和创建 JSON 字典,
但是,我收到一个名为 NSCocoaErrorDomain Code=3840“Garbage at end.”的错误。 由于某些未知原因,解密在 [= 的末尾创建了 [=30=][=30=][=30=][=30=][=30=][=30=] 32=] 字符串(可能是填充)。我正在使用 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}]}[=14=][=14=][=14=][=14=][=14=][=14=]
我的XCode输出是
下面是 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
投影到源字节的字节上,但只投影到第一个字节之前的字节零(或直到结尾,如果没有尾随零)。
我能够以某种最奇怪的方式让它工作,当然有更好的方法来做到这一点,只是张贴在这里以防有人可以添加更好更正确的代码来解决这个问题,因为回答.
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: "[=10=]", 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()
}
})
}
您的代码看起来很奇怪。通常的顺序是:原始数据(例如JSON)+加密+base-64编码+传输+base-64解码+解密->原始数据(例如JSON).
加密会添加一些填充,只要您对两者使用相同的参数,解密就会自动删除这些填充。但是那时你有一个 base-64 编码步骤,在这一点上是完全奇怪的。
并且您被允许将所有处理放入一个单独的函数中。
我有以下功能,我尝试解码(base64)、解密和创建 JSON 字典,
但是,我收到一个名为 NSCocoaErrorDomain Code=3840“Garbage at end.”的错误。 由于某些未知原因,解密在 [= 的末尾创建了 [=30=][=30=][=30=][=30=][=30=][=30=] 32=] 字符串(可能是填充)。我正在使用 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}]}[=14=][=14=][=14=][=14=][=14=][=14=]
我的XCode输出是
下面是 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
投影到源字节的字节上,但只投影到第一个字节之前的字节零(或直到结尾,如果没有尾随零)。
我能够以某种最奇怪的方式让它工作,当然有更好的方法来做到这一点,只是张贴在这里以防有人可以添加更好更正确的代码来解决这个问题,因为回答.
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: "[=10=]", 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()
}
})
}
您的代码看起来很奇怪。通常的顺序是:原始数据(例如JSON)+加密+base-64编码+传输+base-64解码+解密->原始数据(例如JSON).
加密会添加一些填充,只要您对两者使用相同的参数,解密就会自动删除这些填充。但是那时你有一个 base-64 编码步骤,在这一点上是完全奇怪的。
并且您被允许将所有处理放入一个单独的函数中。