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

关于支付宝支付宝的返回值问题, 再一次踩到深坑里, 无论是从返回值的格式上, 还是使用在线的格式化工具验证, 都像是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]以方便使用.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343