美文网首页BUGs
[iOS]关于支付宝支付返回值的坑

[iOS]关于支付宝支付返回值的坑

作者: 流火绯瞳 | 来源:发表于2017-08-05 22:59 被阅读723次

关于支付宝支付宝的返回值问题, 再一次踩到深坑里, 无论是从返回值的格式上, 还是使用在线的格式化工具验证, 都像是JSON字符串, 理论上一定能够转换为字典类型. 但事实却总是不尽如人意.
返回值整体是一个字典, 但使用json格式化工具检查会发现, 格式不对:

支付宝支付结果

这是因为最后一个键值对不完整, 后面加个"", 即"memo": ""

补充完整后的结果

虽然json格式不对, 但是可以正确的获取状态码, 即"resultStatus" 字段是可以正常获取到的, 问题就出在获取结果内容时, 即: "result" 字段对应的内容, 看结构也应该是一个字典, 其内容如下:

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. 有一些多余的字符: \" { } ;
  2. 看似是键值对的之间都是以逗号(,)分割, 可以先以逗号(,)分割字符串, 得到都是键值对的字符数组;
  3. 键和值之间是以冒号分割, 然后再以冒号(:)分割, 得到键和值的数组, 再去取值即可;

注意: 此处的分割依据, 不同的后台写的编码格式, 可能会有不同, 根据自己获取到支付结果来分割即可.

知道了这些就可以去手动分割处理这个字符串了:

  1. 去除多余字符串, 这里是以空字符串替换的形式
//1. 去除字符串内的 \" 
        let str1 = str.replacingOccurrences(of: "\"", with: "")
        // 2. 去除字符串内的 {
        let str2 = str1.replacingOccurrences(of: "{", with: "")
        // 3. 去除字符串内的 }
        let str3 = str2.replacingOccurrences(of: "}", with: "")
  1. 以逗号(,)分割字符串, 得到的是一个键值对的字符串数组
// 4. 以逗号(,)分割字符串, 获取到一个数组
        let arr = str3.components(separatedBy: ",")
  1. 然后遍历这个数组, 对每一个字符串以冒号(:)进行分割, 得到键和值的数组
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]以方便使用.

相关文章

网友评论

  • 本帅不良:很强,我搞这个问题搞了一天,还是搞不出来。
  • 琥珀之剑:为什么回掉结果为空。。。swift3.0
    流火绯瞳:@龍轶绯於 看下后台有没有收到支付结果

本文标题:[iOS]关于支付宝支付返回值的坑

本文链接:https://www.haomeiwen.com/subject/qrdokxtx.html