当前位置: 首页 > 工具软件 > dict_build > 使用案例 >

python中query函数-python构造类http_build_query函数简版

徐淳
2023-12-01

原创作品:首发u3v3, 转载请保留

作者ID:Yi_Zhi_Yu

首发日期:2017.4.13

Python学习群:278529278 (欢迎交流)

前言

在PHP中, 我们使用curl 扩展发送post请求时, 可以通过http_build_query 来构造多维的 post 参数, 用法如下

$request_params = [

'name' => 'Yi_Zhi_Yu',

'scores' => [

['name' => 'English', 'score'=>100],

['name' => 'Math', 'score'=>100]

]];

echo http_build_query($request_params);

输出如下

user=Yi_Zhi_Yu&info%5B0%5D%5Bage%5D=27&info%5B0%5D%5Bsex%5D=man

通过url decode, 即

user=Yi_Zhi_Yu&info[0][age]=27&info[0][sex]=man

这就是post时, 我们需要发送的post body 的内容

PHP 里有http_build_query, 那python中呢,

当然没了, 要不然我就不用自己实现了

问题

python 里, 我们发送post的时候, 如果需要将post body 做url encode, 有一个urllib2模块可以用

if __name__ == '__main__':

request_params = {'name': 'Yi_Zhi_Yu', 'score': 100}

print(urllib.parse.urlencode(request_params))

# name=Yi_Zhi_Yu&score=100

那如果 post 的结构是多维的呢? 看下

if __name__ == '__main__':

request_params = {

'name': 'Yi_Zhi_Yu',

'scores':[

{'name': 'English', 'score': 100},

{'name': 'Math', 'score': 100}

]

}

print(urllib.parse.urlencode(request_params))

输出如下

name=Yi_Zhi_Yu&scores=%5B%7B%27name%27%3A+%27English%27%2C+%27score%27%3A+100%7D%2C+%7B%27name%27%3A+%27Math%27%2C+%27score%27%3A+100%7D%5D

decode 可视化后:

name=Yi_Zhi_Yu&scores=[{'name': 'English', 'score': 100}, {'name': 'Math', 'score': 100}]

name 还算正常, scores直接是个json格式了

post 请求发送出去后, 需要服务端 decode 才能用

我们期望的格式应该是类似于PHP http_build_query的结果

name=Yi_Zhi_Yu&scores[0][name]=English&scores[0][score]=100&scores[1][name]=Math&scores[1][score]=100

服务端通过POST获取后, 直接就可以作为数组使用

为此, 我实现了一个简单的版本

解决

直接看代码

import urllib.parse

def url_encoder(params):

g_encode_params = {}

def _encode_params(params, p_key=None):

encode_params = {}

if isinstance(params, dict):

for key in params:

encode_key = '{}[{}]'.format(p_key,key)

encode_params[encode_key] = params[key]

elif isinstance(params, (list, tuple)):

for offset,value in enumerate(params):

encode_key = '{}[{}]'.format(p_key, offset)

encode_params[encode_key] = value

else:

g_encode_params[p_key] = params

for key in encode_params:

value = encode_params[key]

_encode_params(value, key)

if isinstance(params, dict):

for key in params:

_encode_params(params[key], key)

return urllib.parse.urlencode(g_encode_params)

看测试代码

if __name__ == '__main__':

request_params = {'name': 'Yi_Zhi_Yu',

'scores':[

{'name': 'English', 'score': 100},

{'name': 'Math', 'score': 100}

]

}

#print(urllib.parse.urlencode(request_params))

print(url_encoder(request_params))

输出结果经过decode后如下

scores[1][score]=100&scores[0][score]=100&scores[1][name]=Math&scores[0][name]=English&name=Yi_Zhi_Yu

服务端在接受到这个POST bod以后, 也可以直接作为数组使用, 请求格式与PHP的 http_build_query基本类似

不过这里有个问题是, url encode后的参数顺序与原始的request params 不一样了

这个是因为python的dict本身是无序的, 如果要求有序, 大家可以把默认的dict 替换为OrderDict

这个作为一个小作业吧, 后续有时间, 我会贴出来结果的

:)

误区

这里还有一个关于PHP的常见误区, 当客户端发起的post请求中, header 的content-type 被设置成了 application/json时, 很多人认为, 在PHP的Server端, 用$_POST就能获取json的请求格式数据了

然而并非如此, 这种时候, PHP只能通过

$json = file_get_contents('php://input');

$obj = json_decode($json);

获取 json 的数据

 类似资料: