关于支付宝支付宝的返回值问题, 再一次踩到深坑里, 无论是从返回值的格式上, 还是使用在线的格式化工具验证, 都像是JSON字符串, 理论上一定能够转换为字典类型. 但事实却总是不尽如人意.
返回值整体是一个字典, 但使用json格式化工具检查会发现, 格式不对:
这是因为最后一个键值对不完整, 后面加个"", 即"memo": ""
虽然json格式不对, 但是可以正确的获取状态码, 即"resultStatus" 字段是可以正常获取到的, 问题就出在获取结果内容时, 即: "result" 字段对应的内容, 看结构也应该是一个字典, 其内容如下:
怎么看怎么都是个字典, 但是使用如下方式转换的时候:
guard let result: Dictionary<String, Any> = resultDic?["result"] as? Dictionary<String, Any> else {
printLog(message: "error return")
return
}
其结果总是nil, 怎么都不能转换为字典. 后来查了一些资料, 说这个字段对应的是一个字符串, 需要自己分割去获取相应的结果. 尝试转成字符串试试:
let obj = resultDic?["result"]
let obj1 = obj as? String
obj1 正确转换为一个字符串, 不过这个字符串是这样的:
{\"alipay_trade_app_pay_response\":{\"code\":\"10000\",\"msg\":\"Success\",\"app_id\":\"2017012354656320\",\"auth_app_id\":\"2017098762379652\",\"charset\":\"UTF-8\",\"timestamp\":\"2017-07-26 15:27:39\",\"total_amount\":\"0.01\",\"trade_no\":\"2017080531001004110233498754\",\"seller_id\":\"2088376896937865\",\"out_trade_no\":\"2017080417556432152031721246532\"},\"sign\":\"XWwmxNraskQcaXx/8YL+lf6yWy0/Ws+hAIXxSznZfLM9C1kmcWcQ00PLteIctdI35yF3N4HdkVbGI697qMQbJiPZ+1yHGe1e3UXfqX7LUrVUN5M4hgXnPDf8ekHdPlLVnPeDrTKD3IcPXq5SU5d9U7kytGYQjx6LeHUuG/Oa3N/5pQXmr8xIf5z/kOiHCrXYEW7Eq4FVobliGRfKF2pSaB00Dt9zHTUSMPjw5KVfcM9D/ecniLbu8NtQ1y/mRalUIkDQ1HMNYAhinhUcxB6SHIkeenbeS67/TsrDYTIZoNKpMfY/8jqY+Yc8wwfkZFJYjjZCPuM8tvjCWOTMy/kcXA==\",\"sign_type\":\"RSA2\"}
绕了一大圈, 却只能获得一个字符串, 看到这个结果, 我是懵逼的, 这怎么搞? 没办法, 不能搞也得搞, 硬着头皮上吧;
接下来就需要我们手动去处理这个字符串, 来获取我们需要的信息.
一般我们想到的都是最好能转换成一个字典, 这样也方便我们去使用. 那到底能不能转换成字典呢? 直接转换是不行的, 下面我使用两种方式来处理这个结果:
方式一: 分割字符串
分割字符串后保存成字典时可以的.
回头看看这个字符串的格式:
- 有一些多余的字符: \" { } ;
- 看似是键值对的之间都是以逗号(,)分割, 可以先以逗号(,)分割字符串, 得到都是键值对的字符数组;
- 键和值之间是以冒号分割, 然后再以冒号(:)分割, 得到键和值的数组, 再去取值即可;
注意: 此处的分割依据, 不同的后台写的编码格式, 可能会有不同, 根据自己获取到支付结果来分割即可.
知道了这些就可以去手动分割处理这个字符串了:
- 去除多余字符串, 这里是以空字符串替换的形式
//1. 去除字符串内的 \"
let str1 = str.replacingOccurrences(of: "\"", with: "")
// 2. 去除字符串内的 {
let str2 = str1.replacingOccurrences(of: "{", with: "")
// 3. 去除字符串内的 }
let str3 = str2.replacingOccurrences(of: "}", with: "")
- 以逗号(,)分割字符串, 得到的是一个键值对的字符串数组
// 4. 以逗号(,)分割字符串, 获取到一个数组
let arr = str3.components(separatedBy: ",")
- 然后遍历这个数组, 对每一个字符串以冒号(:)进行分割, 得到键和值的数组
for tmp in arr {
let tmpArr = tmp.components(separatedBy: ":")
}
这时的结果数组里就包含键值两个字符串, 仔细观察会发现, 这些小数组中有一个(第一个)是包含了三个元素的, 其余的都是2个元素, 然后, 以字典的形式来重新保存这些键值对:
for tmp in arr {
let tmpArr = tmp.components(separatedBy: ":")
// 这时的结果
if tmpArr.count == 2 {
let key = tmpArr[0]
let value = tmpArr[1]
dic[key] = value
} else if tmpArr.count == 3 {
let key = tmpArr[1]
let value = tmpArr[2]
dic[key] = value
}
}
完整的代码如下, 最后返回一个正常的字典:
class func changeStringResultToDic(_ str: String) -> Dictionary<String, String> {
//1. 去除字符串内的 \" , 这里是以空字符串替换的形式
let str1 = str.replacingOccurrences(of: "\"", with: "")
// 2. 去除字符串内的 {
let str2 = str1.replacingOccurrences(of: "{", with: "")
// 3. 去除字符串内的 }
let str3 = str2.replacingOccurrences(of: "}", with: "")
// 4. 以逗号(,)分割字符串, 获取到一个数组
let arr = str3.components(separatedBy: ",")
var dic: [String: String] = [:]
// 5. 遍历这个数组, 然后再以 : 来分割子字符串
for tmp in arr {
let tmpArr = tmp.components(separatedBy: ":")
// 这时的结果
if tmpArr.count == 2 {
let key = tmpArr[0]
let value = tmpArr[1]
dic[key] = value
} else if tmpArr.count == 3 {
let key = tmpArr[1]
let value = tmpArr[2]
dic[key] = value
}
}
return dic
}
方式二: 先转成Data, 然后再去解析为Dictionary
最简单的方式是使用下面的方法先转换为utf8编码的Data数据, 然后再使用JSONSerialization的方法来解析这个JSON数据为字典对象:
if let data = str.data(using: String.Encoding.utf8) {
if let dic1 = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any] {
print(dic1)
print(dic1!["alipay_trade_app_pay_response"]["out_trade_no"])
}
}
不过, 这种方式解析出来的字典不是以[String: String]方式的键值对, 而是[String: Any], 最好在这里处理成[String: String]以方便使用.