接口测试 关于在 python 中使用 requests 框架传入中文参数问题

testBlue · 2017年03月16日 · 最后由 tester_lv 回复于 2019年11月18日 · 4462 次阅读
def requestsMethodForPost(param):
    url = upGradeUrl + '?'
    request = requests.post(url, data=param)
    response = request.text
    print response
    respDic = json.loads(response)
    return respDic

大神们,我用 python 做接口自动化测试,遇到这么一个问题,在用 requests 中 post 请求的时候,参数中会带有中文,然后我就直接把中文传进去了:

params = {
    'from':'internal',
    'gps_type':'baidu',
    'lat':'40.018597',
    'lng':'116.476326',
    'mac':'b4:30:52:5e:6d:61',
    'model':'HUAWEI-HUAWEI C8817E',
    'name':'先生',
    'order_id':self.order_id,
    'os':'HUAWEI19,4.4.4',
    'phone':'13000000090',
}

然后,我就 post 出这个请求,但是在控制台,这个中文被直接自动转换为'\xe5\x85\x88\xe7\x94\x9f',导致这个传参一直是错误的,服务端会去校验你传入的值是否为正确编码格式,而 python 默认不会直接传入中文数据,这个有人遇到过吗

最佳回复

假如服务端是接受 GBK 编码,对于 python 3 来说,中文 POST 参数应这样写
```python 3
#requests (2.18.4)

'name': '先生'.encode('GBK'), # 生成 bytes 类型,而不要用 str。因为 str 会默认由 utf-8 编码。如果服务端也用 UTF-8 解码中文,应该不会有问题。

以下是models.py原文 在site-packages\requests 目录下

```python
    def _encode_params(data):
        """Encode parameters in a piece of data.

        Will successfully encode parameters when passed as a dict or a list of
        2-tuples. Order is retained if data is a list of 2-tuples but arbitrary
        if parameters are supplied as a dict.
        """

        if isinstance(data, (str, bytes)):
            return data
        elif hasattr(data, 'read'):
            return data
        elif hasattr(data, '__iter__'):
            result = []
            for k, vs in to_key_val_list(data):
                if isinstance(vs, basestring) or not hasattr(vs, '__iter__'):
                    vs = [vs]
                for v in vs:
                    if v is not None:
                        result.append(
                            (k.encode('utf-8') if isinstance(k, str) else k,
                             v.encode('utf-8') if isinstance(v, str) else v))
            return urlencode(result, doseq=True)
        else:
            return data


关键位置在于对 k,v 的处理,所以假如提供的是,b'\xcf\xc8\xc9\xfa' 这样的数据,会原样传给服务器。
但是假如服务器也是 UTF-8 处理中文,则完全不用这样。这样服务器接收到的 name 值就是'先生'.encode('utf-8') .也许是 b'\xe5\x85\x88\xe7\x94\x9f'。
然后它还要经过 urldecode 处理以后,再反向解析成中文字符串。就是你看到的这个样子'\xe5\x85\x88\xe7\x94\x9f' 这就是 name 参数的内存格式。
假如控制台只能接受和显示 GB2312、 要对这个字符串做 utf-8 转 GBK 的处理才能显示出来了。

这是两个关于汉字编码的地址可做参考
http://www.cnblogs.com/ttltry-air/p/3325543.html
https://www.zhihu.com/question/26921730

共收到 17 条回复 时间 点赞

感觉这个跟 post 请求没关系,看看有没有在文件开头加上 #coding=utf-8

—— 来自 TesterHome 官方 安卓客户端

无忧~ 回复

还真是加了的,# -- coding: utf8 --
但是还是不太行啊,他关键会自己转换

  • 在中文前面加个
'name':u'先生',

试一下。

可以使用 fiddler 抓包下你 post 的数据,查看下是否正确。Inspectors→webForms→bodydata

编码编码,格式转换,你先问一下,接口接受的默认编码是啥子,然后转换你的参数后在传递

我觉得接口测试中,你还要考虑加解密的封装,正则匹配,特别是断言的正则匹配

0x7C00 回复

这个我还真试过了,结果是 unicode 类型字符串,还是不能通过接口测试

json.dumps( params, ensure_ascii = False, separators = (',', ':') )

路人荚 回复

对了,多问您一句,您平时断言怎么写的,比如正常接口返回值 code=0,然后当我任意传递参数不正确的时候返回 code 值为 1,那我断言就写一个正确的传参用例和几个错误的传参用例,当错误的时候,self.assertEqual(respDic['code'],1),符合预期用例通过,但是,明显的我服务器这时候是有问题的啊,他返回非零就是有问题的但是我用例跑通过了,这如何能抓到服务的错误,感觉很矛盾啊

换 python 3 试试

大桥 回复

python3 网上说是可以的,但是如果换的话感觉有些格式的编写就需要修改,不是太方便,当然也是可以解决这个问题的,辛苦

路人荚 回复

我试了下目前情况是这样的,接口测试用 post 请求的时候,当我直接打印 param 中的信息的时候,中文就直接被转为 16 进制了,当我 param['name'] 的时候,就会打印出中文,很纳闷啊

把中文先编码,然后再组装到 json 里试试

假如服务端是接受 GBK 编码,对于 python 3 来说,中文 POST 参数应这样写
```python 3
#requests (2.18.4)

'name': '先生'.encode('GBK'), # 生成 bytes 类型,而不要用 str。因为 str 会默认由 utf-8 编码。如果服务端也用 UTF-8 解码中文,应该不会有问题。

以下是models.py原文 在site-packages\requests 目录下

```python
    def _encode_params(data):
        """Encode parameters in a piece of data.

        Will successfully encode parameters when passed as a dict or a list of
        2-tuples. Order is retained if data is a list of 2-tuples but arbitrary
        if parameters are supplied as a dict.
        """

        if isinstance(data, (str, bytes)):
            return data
        elif hasattr(data, 'read'):
            return data
        elif hasattr(data, '__iter__'):
            result = []
            for k, vs in to_key_val_list(data):
                if isinstance(vs, basestring) or not hasattr(vs, '__iter__'):
                    vs = [vs]
                for v in vs:
                    if v is not None:
                        result.append(
                            (k.encode('utf-8') if isinstance(k, str) else k,
                             v.encode('utf-8') if isinstance(v, str) else v))
            return urlencode(result, doseq=True)
        else:
            return data


关键位置在于对 k,v 的处理,所以假如提供的是,b'\xcf\xc8\xc9\xfa' 这样的数据,会原样传给服务器。
但是假如服务器也是 UTF-8 处理中文,则完全不用这样。这样服务器接收到的 name 值就是'先生'.encode('utf-8') .也许是 b'\xe5\x85\x88\xe7\x94\x9f'。
然后它还要经过 urldecode 处理以后,再反向解析成中文字符串。就是你看到的这个样子'\xe5\x85\x88\xe7\x94\x9f' 这就是 name 参数的内存格式。
假如控制台只能接受和显示 GB2312、 要对这个字符串做 utf-8 转 GBK 的处理才能显示出来了。

这是两个关于汉字编码的地址可做参考
http://www.cnblogs.com/ttltry-air/p/3325543.html
https://www.zhihu.com/question/26921730

您好,python requests 接口测试,根据 postman 得到的参数 payload 里还有中文,执行后会报错。UnicodeEncodeError: 'latin-1' codec can't encode characters in position 179-182: Body ('并驾齐驱') is not valid Latin-1. Use body.encode('utf-8') if you want to send it encoded in UTF-8.请问大牛是怎么解决的?

曹鹏 回复

我也遇到了同样的问题,我的中文是一个 value 值,执行 unittest 就报错

曹鹏 回复

post 里面把 data=payload 改成 data=payload.encode('utf-8') 试试!

上边的说法都试了一遍,为啥还是不行,请求发送之后还是 byte 格式

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册