如何在Python2 Requests的json参数中设置UTF-8编码处理中文?
解决Python2中requests使用json参数发送中文到BigIP的PATCH请求问题
核心问题原因
在Python2环境下,requests库处理json参数时,默认调用json.dumps()且启用ensure_ascii=True,会将所有非ASCII字符(比如中文)转换为\uXXXX格式的Unicode转义序列。而BigIP的API可能无法正确解析这种转义后的JSON格式,导致返回400错误("double quotes are not balanced")。
此外,如果你提前将Unicode字符串编码为UTF-8字节串再传入json参数,json.dumps()会把字节串中的非ASCII字节再次转义,生成双重转义的JSON,进一步触发解析错误。
解决方案
方案1:猴子补丁修改requests的JSON序列化逻辑(适配固定使用json参数的场景)
如果底层代码固定要求使用json参数,无法直接切换到data参数,可以通过猴子补丁修改requests的请求体处理逻辑,强制使用ensure_ascii=False进行JSON序列化:
import requests import json # 替换原有的prepare_body方法 original_prepare_body = requests.models.Request.prepare_body def patched_prepare_body(self, data, files, json=None): if json is not None: # 手动序列化JSON,禁用ASCII转义 import complexjson body = complexjson.dumps(json, ensure_ascii=False) if not isinstance(body, bytes): body = body.encode('utf-8') # 调用原方法,传入处理好的字节体 return original_prepare_body(self, body, files, json=None) return original_prepare_body(self, data, files, json) requests.models.Request.prepare_body = patched_prepare_body # 原有业务代码(注意不要提前encode中文) # -*- coding: utf-8 -*- import base64 url = "https://10.13.7.17/mgmt/tm/ltm/virtual/~Project_6fd06a50b7824ae48386565786e94b38~test" test2 = u"bu退" # 直接传递Unicode字符串,无需提前编码 data = {"description": test2} headers = { 'Authorization': 'Basic YWRamdflk6YWRtaW5Aasdlfjkla', } response = requests.request("PATCH", url, headers=headers, json=data, verify=False) print(response.text)
方案2:手动序列化JSON并使用data参数(推荐,若允许修改参数类型)
如果可以修改请求参数类型,直接手动控制JSON序列化过程,生成UTF-8编码的原始JSON字节,通过data参数发送:
# -*- coding: utf-8 -*- import requests import json import base64 url = "https://10.13.7.17/mgmt/tm/ltm/virtual/~Project_6fd06a50b7824ae48386565786e94b38~test" test2 = u"bu退" data = {"description": test2} # 手动序列化,禁用ASCII转义并编码为UTF-8字节 payload = json.dumps(data, ensure_ascii=False).encode('utf-8') headers = { 'Authorization': 'Basic YWRamdflk6YWRtaW5Aasdlfjkla', 'Content-Type': 'application/json' # 必须指定内容类型 } response = requests.request("PATCH", url, headers=headers, data=payload, verify=False) print(response.text)
验证逻辑
在Python2中,不同序列化方式的结果对比:
# 原始数据(Unicode字符串) data = {"description": u"bu退"} # 默认序列化:转义非ASCII字符 json.dumps(data) # 输出: '{"description": "bu\\u9000"}' # 禁用ASCII转义:保留原始字符 json.dumps(data, ensure_ascii=False) # 输出: u'{"description": "bu\u9000"}' # 编码为UTF-8字节:适合直接发送给服务器 json.dumps(data, ensure_ascii=False).encode('utf-8') # 输出: '{"description": "bu\xe9\x80\x80"}'
方案1和方案2最终都会生成最后一种格式的请求体,符合BigIP API的解析要求。
内容的提问来源于stack exchange,提问作者Pzhang
相关产品推荐
相关产品推荐

