最近做需求时候, 遇到一个后端联调问题, 需求是 后端A 把一个 json 转成 string 后放到 scheme 的payload参数中, json 如下, text1 是一个字符串,
1 | { |
转换为字符串payload后变成
1 | {\"text1\":\"今天是个好日子\",\"trackID1\":123456} |
scheme 大致如下:
1 | scheme://test/ui/func?p={"hintPayload":"{\"text1\":\"今天是个好日子\",\"trackID1\":123456}","param2":"9"} |
然后对 scheme 转义, 下发给客户端, 客户端在解析 scheme 后, 获取各个参数, 然后把payload 字符串给另一个业务后端B.
自测阶段没什么问题, 但是测试发现text1中有换行符以及"时候就不行了, 客户端问题就出在解析 scheme 时候, 会对参数做一次 string 转 json 处理, 这次处理失败了.
报错如下
1 | parse json error(Error Domain=NSCocoaErrorDomain Code=3840 "Unescaped control |
意思是text1的第 42 个字符有问题, (注意这里是从 0 开始数的, 但是把有问题的字符串贴到编辑器, 编辑器大多是从 1 开始数的)
客户端 scheme 解析出错
找到有问题的字符是 %0A, 换行符, 嗯, easy, 让 后端A 把 %0A 换成 \\n 下发就好, 经过 scheme 反转义后会变成 \n
很快遇到第二个问题, " 也有问题, 行, 再让 后端A 换成\\"下发, 经过 scheme 反转义后变成\", 客户端终于能解析 scheme 了.
注: iOS 解析
%0A以及"出错, Android 解析"出错
后台解析也出错
然后就遇到第三个问题, 当把从 scheme 里面解析出来的payload 给另一个业务 后端B 时候, 转json 就失败了,
第一个问题是 字符串里直接是 \n 后端解析不了,
第二个问题是 \"后端也解析不了
这里尝试客户端做下兼容, \n 换成 \\n, easy,,,
但是 \"处理就麻烦了, payload字符串如下,
1 | { \"text1\": \"今天是个好日子\"有引号\", \"trackID1\": 123456 } |
text1 中有\", 参数 text1/trackID1后面也有\", 直接对字符串处理肯定是不行的
那还得先把 payload 转成 json, 再对其中的值做 \"的转换, 最后再把 json 转成字符串给到后端B.
疯了吧
最后回想下上面,
- 后端A 做了两个字符串的处理,
- 客户端(iOS / Anrdoid) 两端都也要处理,
- 本不该客户端理解的
payload字段客户端也得做一次 json 化, 然后处理其中的值, - 还有其他字符有问题吗???
怎么看这个思路都有大问题
追溯源头
回到最开始的问题, 客户端居然在 scheme 中的参数解析出了 %0A, 百分号字符是 URL 转义的, 客户端在对 scheme 做了反转义之后, 根本不应该还有 %0A呀? 后端A 下发的 scheme 有问题, 问后端 A scheme 是怎么拼出来的, 答曰: 前端提供的, 直接替换了某些字段, 就转义然后给了客户端.
前端提供的 scheme 如下:
1 | scheme://test/ui/func?p={"hintPayload":"{\"text1\":\"text1Value\",\"trackID1\":trackID1Value}","param2":"9"} |
后端A 使用上面的 scheme 直接把 text1Value 以及trackID1Value 换成了需要的值, 然后转义下就给了客户端. 所以 text1Value 中的特殊字符根本没有被处理过, 直接一起被转义了, 导致了前面一串的问题.
解决
解决问题总是很无聊的, 后台对 scheme 的处理改为
- 使用需要的值, 构造了 json
- json 转为字符串
- 字符串放在了 scheme 后面的参数中
- 转义给了客户端
好像一开始就应该这么做吧? 这反应一个普遍问题, scheme 是前端和客户端的交互的协议, 后端一般不愿意去理解, 最后在实践中也的确没有去理解, 直接通过字符串替换的方式完成了需求, 最后导致了联调问题.