今日联调接口,用python2和Java分别调用,一样的流程结果却不同,做个记录。
该接口是一个http请求,需要将参数进行base64编码,再组成一个json串,再对json串进行url编码,将最终的编码结果进行传输。(没错就是这么复杂 -_-!!)
比对python2和Java代码组成的最终参数,发现长度和内容不一致。查询后发现几个差异点:
1,Java转base64,内容中增加了许多回车换行符( 即'\r\n')。
查询原因:
据RFC 822规定,每76个字符,还需要加上一个回车换行
有时就因为这些换行弄得出了问题,解决办法就是把回车换行都清除掉
2,python2转换的参数增加了部分空格,且斜杠'/'没有转换,究其原因在于代码中使用的函数。
import urllib
import base64
import json
fp = open(picture_path, 'rb')
fbuf = fp.read()
fp.close()
picture_base64 = base64.b64encode(fbuf)
data = {"day":"Sunday","activity":"Swimming","picture":picture_base64}
json_str = json.dumps(data) # dict结构转化为json串
param = urllib.quote(json_str) # 进行url编码
(1)json.dumps转化,会在键值对中加入空格,如上代码转换格式后就是:
data = {"day":"Sunday",(空格)"activity":"Swimming",(空格)"picture":picture_base64}
将字符串再处理去掉空格就行了
(2)url编码函数quote用法
查询函数定义:
urllib.quote(string [, safe])
将string中的特殊字符转化为%xx的格式,其中字母、数字和 '_.-'不会被转化。可选参数safe后面可以增加不想被转化的字符,默认值是'/'.
所以在上述代码中,最终转化出来的字符串中依然有斜杠,与Java代码不同。
改为param = urllib.quote(json_str, safe='') 就OK了
(2.1)扩展
urllib.quote若想多个字符不想被转化,可以直接在safe参数添加,
如不想转化‘+’和‘=’,只需urllib.quote(string, safe='+=')
(2.2) 扩展2
python2中有另一个url编码函数:urllib.quote_plus。该函数默认会转化斜杠,但会把空格转化为‘+’号
查询发现,该函数其实也是调用了quote,只是safe传空,并对空格进行了处理
# quote_plus源码
def quote_plus(s, safe=''):
"""Quote the query fragment of a URL; replacing ' ' with '+'"""
if ' ' in s:
s = quote(s, safe + ' ')
return s.replace(' ', '+')
return quote(s, safe)
(2.3) 扩展3:为何空格有的会转化为'+'号
查询发现,源于两种不同的标准。
W3C标准规定,当Content-Type为application/x-www-form-urlencoded时,URL中查询参数名和参数值中空格要用加号+替代,所以几乎所有使用该规范的浏览器在表单提交后,URL查询参数中空格都会被编成加号+。
另一份规范(RFC 2396,定义URI)里, URI里的保留字符都需转义成%HH格式(Section 3.4 Query Component),因此空格会被编码成%20,加号+本身也作为保留字而被编成%2B,对于某些遵循RFC 2396标准的应用来说,它可能不接受查询字符串中出现加号+,认为它是非法字符。
所以一个安全的举措是URL中统一使用%20来编码空格字符。
参考链接:https://blog.csdn.net/xuebing1995/article/details/80664450
一个联调搞了好久,还是要注重细节。。=_=!!