python的http发送JSON包传输以及中文问题

几天做一个很小的测试Demo,任务为调用HTTP的post方法,测试HTTP服务的几个接口的功能,并进行极限测试。

程序很快写完了,但发现几个接口测试一直出问题,最关键的是:JSON校验一直出问题。

JSON校验的原理是网络传输的校验的通用方法:JSON数据+密钥,统一为UTF8形式,然后进行MD5加密,生成数据签名。在服务端进行校验数据是否被修改了。

对JSON进行加密的方法如下所示:

def produce_sign(data):
    sign_src = (json.dumps(data) + APP_SECRET).encode(encoding='utf-8')

    md5 = hashlib.md5()
    md5.update(sign_src)

    return md5.hexdigest()

最后发现原来是数据转JSON的时候出问题了。总结发现是json.dumps函数本身的问题。

json.dumps在转换字典数据的时候,会自然带空格进去,而且,默认字符为ASCII码。

查python的官方文档(https://docs.python.org/zh-cn/3/library/json.html),大致可以得出如下信息:

json.dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)
使用这个 转换表 将 obj 序列化为 JSON 格式化流形式的 fp (支持 .write() 的 file-like object)。

如果 skipkeys 是 true (默认为 False),那么那些不是基本对象(包括 str, int、float、bool、None)的字典的键会被跳过;否则引发一个 TypeError。

json 模块始终产生 str 对象而非 bytes 对象。因此,fp.write() 必须支持 str 输入。

如果 ensure_ascii 是 true (即默认值),输出保证将所有输入的非 ASCII 字符转义。如果 ensure_ascii 是 false,这些字符会原样输出。

如果 check_circular 是为假值 (默认为 True),那么容器类型的循环引用检验会被跳过并且循环引用会引发一个 OverflowError (或者更糟的情况)。

如果 allow_nan 是 false(默认为 True),那么在对严格 JSON 规格范围外的 float 类型值(nan、inf 和 -inf)进行序列化时会引发一个 ValueError。如果 allow_nan 是 true,则使用它们的 JavaScript 等价形式(NaN、Infinity 和 -Infinity)。

如果 indent 是一个非负整数或者字符串,那么 JSON 数组元素和对象成员会被美化输出为该值指定的缩进等级。如果缩进等级为零、负数或者 "",则只会添加换行符。None``(默认值)选择最紧凑的表达。使用一个正整数会让每一层缩进同样数量的空格。如果 *indent* 是一个字符串(比如 ``"\t"),那个字符串会被用于缩进每一层。

在 3.2 版更改: 允许使用字符串作为 indent 而不再仅仅是整数。

当指定时,separators 应当是一个 (item_separator, key_separator) 元组。当 indent 为 None 时,默认值取 (', ', ': '),否则取 (',', ': ')。为了得到最紧凑的 JSON 表达式,你应该指定其为 (',', ':') 以消除空白字符。

在 3.4 版更改: 现当 indent 不是 None 时,采用 (',', ': ') 作为默认值。

当 default 被指定时,其应该是一个函数,每当某个对象无法被序列化时它会被调用。它应该返回该对象的一个可以被 JSON 编码的版本或者引发一个 TypeError。如果没有被指定,则会直接引发 TypeError。

如果 sort_keys 是 true(默认为 False),那么字典的输出会以键的顺序排序。

为了使用一个自定义的 JSONEncoder 子类(比如:覆盖了 default() 方法来序列化额外的类型), 通过 cls 关键字参数来指定;否则将使用 JSONEncoder。

在 3.6 版更改: 所有的可选参数现在是 keyword-only 的了。

注解 与 pickle 和 marshal 不同,JSON 不是一个具有框架的协议,所以尝试多次使用同一个 fp 调用 dump() 来序列化多个对象会产生一个不合规的 JSON 文件。
json.dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)
使用这个 转换表 将 obj 序列化为 JSON 格式的 str。 其参数的含义与 dump() 中的相同。

注解 JSON 中的键-值对中的键永远是 str 类型的。当一个对象被转化为 JSON 时,字典中所有的键都会被强制转换为字符串。这所造成的结果是字典被转换为 JSON 然后转换回字典时可能和原来的不相等。换句话说,如果 x 具有非字符串的键,则有 loads(dumps(x)) != x。

显然,应该设置ensure_ascii为False;同时,对分隔符进行合理区分。

文档的注释说明:“separators 应当是一个 (item_separator, key_separator) 元组。”其中,item_separator为一个JSON项的分割符, key_separator为JSON的key-value值的分隔符。

显然,合理的JSON应该是逗号作为一个JSON项的分隔符,冒号作为key-value值的分隔符。

代码如下:

def produce_sign(data):
    sign_src = (json.dumps(data, ensure_ascii=False, separators=(',', ':')) + '|' + APP_SECRET).encode(encoding='utf-8')

    md5 = hashlib.md5()
    md5.update(sign_src)

    return md5.hexdigest()

其中,md5 = hashlib.md5() md5.update(sign_src) return md5.hexdigest()   是md5加密过程。

发现进行post发送,依然存在问题。报这个错误“UnicodeEncodeError: 'latin-1' codec can't encode character '\u4eac' in position 125: Body ('京') is not valid Latin-1”

原来是post数据时,不能发送含有汉字的字母。

解决思路:用utf8格式发送。

 r = requests.post(URL, headers=h, data=json.dumps(d, ensure_ascii=False).encode(encoding='UTF-8'))

然后,数据正确。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值