事情的起因是:有一个创建日程的接口,创建人和参与人,都需要websocket推送一条日程更新信息;现在要测试这个推送名单是否正确,所以要用python写一个创建日程的post请求,指定参与者,即下面代码中的attendees。
开始写好代码的时候,没有添加参与人,即 "attendees": [],跑下来没毛病,日程创建成功!
于是,接下来就添加了参与人,准备做最后一件事情,校验ws收到消息的名单是否和参与人一致;attendees参数如下:
"attendees": [{"cp_id": 154}, {"cp_id": 454}, {"cp_id": 356}]
问题来了!报错了!!!
content: {'code': 40099, 'msg': 'Invalid argument supplied for foreach()(0)', 'data': []}
只是添加上了attendees的值而已,刚才还能请求成功呢?
参数格式也是对的啊,把body拷贝到Apifox发送,日程是能创建成功的...... 于是我,除了傻眼只有迷茫好吗!先贴上代码:
def create_schedule(instance_id, cp_id):
url = "http://cpapi.st1.2345.cn/widget/calendar_b/instances/%s/createSchedule?tdusername=&tdcpid=%s" % (instance_id, cp_id)
body = {
"summary": "test",
"start_date": "2020-12-16 09:00",
"end_date": "2020-12-17 10:00",
"location": "",
"repeat_type": -1,
"remind_before_event_secs": 900,
"attendees": [{"cp_id": 154}, {"cp_id": 454}, {"cp_id": 356}],
"origin_start_date": "2020-12-16 09:00:00",
"description": ""
}
response = requests.post(url,data=body)
content = response.json()
print("content:", content)
if content['code'] == 0 and content['msg'] == 'success':
print("日程创建成功,body:", body)
if __name__ == '__main__':
create_schedule(11, 22)
找报错原因,猜测是不是attendees结构复杂,是字典里面嵌套列表又嵌套字典,于是搜索python的post请求body嵌套列表报错,还真找到一个和我这个body结构一毛一样的,开心!
该博主的解决方式是,把整个列表json.dumps()处理下:
修改下attendees:
"attendees": [{"cp_id": 154}, {"cp_id": 454}, {"cp_id": 356}]
运行,还是报错?!!
content: {'code': 40099, 'msg': 'Invalid argument supplied for foreach()(0)', 'data': []}
那会不会是整个body格式都不对,恢复attendees把post请求里的body参数dumps一下:
response = requests.post(url,data=json.dumps(body))
还是报错,不过报错变了:
content: {'code': 56001, 'msg': '开始时间不能为空', 'data': []}
'开始时间不能为空' 这个报错,是start_date没有传或者start_date为空时提示,而我传的start_date是有值的,说明这个格式转换行不通。
而且我一直耿在attendees为空列表的时候是可以请求成功的,所以我觉得其他内容肯定是没问题的,问题就出在了attendees这个参数值上,感觉是代码处理这个参数的时候没取到值。全部改回去,打印看下请求的body值,打印结果如下:
summary=test&start_date=2020-12-16+09%3A00&end_date=2020-12-17+10%3A00&location=&repeat_type=-1&remind_before_event_secs=900&attendees=cp_id&attendees=cp_id&attendees=cp_id&origin_start_date=2020-12-16+09%3A00%3A00&description=
我cp_id的值呢?于是更坚信了是这个参数导致的请求失败。。。。(后面知道这个参数是无辜的,所以提醒我们,找问题思维要发散...)
中间略去各种找攻略找解决办法,因为结果都是,没解决!!!
感觉没想法了,代码怎么看都没毛病,只好去看看apifox的请求,跟我代码请求到底哪里不一样,我全抄上行吧!
apifox发送好请求只好,requests信息如下:
请求 URL:
POSThttp://cpapi.st1.2345.cn/widget/calendar_b/instances/6593/createSchedule?tdusername=&tdcpid=183
Headers:
名称 值 Authorization 【删掉了】 User-Agent apifox/1.0.24 (https://www.apifox.cn) Content-Type application/json Accept */* Cache-Control no-cache Host cpapi.st1.2345.cn Accept-Encoding gzip, deflate, br Connection keep-alive Content-Length 317 Body:
Body 类型:application/json
{ "summary": "test", "start_date": "2020-12-16 09:00", "end_date": "2020-12-17 10:00", "location": "", "repeat_type": -1, "remind_before_event_secs": 900, "attendees": [{"cp_id": 154}, {"cp_id": 454}, {"cp_id": 356}], "origin_start_date": "2020-12-16 09:00:00", "description": "" }
嗯,headers参数好多哦,可是身份认证也不是用的Authorization(因为是debug模式),其他参数好像也没啥特别的,
主要是没加参与人的时候也没headers,请求没毛病啊!
这里的body的类型提示是 application/json,难道代码请求的body参数被默认成了别的类型?!加个打印,看下headers信息
print(content, response.request.headers, response.request.body)
打印出来这样,看第二行:
{'code': 40099, 'msg': 'Invalid argument supplied for foreach()(0)', 'data': []}
{'User-Agent': 'python-requests/2.24.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '227', 'Content-Type': 'application/x-www-form-urlencoded'} summary=test&start_date=2020-12-16+09%3A00&end_date=2020-12-17+10%3A00&location=&repeat_type=-1&remind_before_event_secs=900&attendees=cp_id&attendees=cp_id&attendees=cp_id&origin_start_date=2020-12-16+09%3A00%3A00&description=
额,还真是,content_type 是 application/x-www-form-urlencoded,可能就是这个原因导致body参数解析异常!赶紧加下headers,加完headers,记得此时body参数要转化为json:
def create_schedule(instance_id, cp_id):
url = "http://cpapi.st1.2345.cn/widget/calendar_b/instances/%s/createSchedule?tdusername=&tdcpid=%s" % (instance_id, cp_id)
body = {
"summary": "test",
"start_date": "2020-12-16 09:00",
"end_date": "2020-12-17 10:00",
"location": "",
"repeat_type": -1,
"remind_before_event_secs": 900,
"attendees": [{"cp_id": 154}, {"cp_id": 454}, {"cp_id": 356}],
"origin_start_date": "2020-12-16 09:00:00",
"description": ""
}
headers = {
"Content-Type": "application/json"
}
response = requests.post(url, headers=headers, data=json.dumps(body))
content = response.json()
if content['code'] == 0 and content['msg'] == 'success':
print("日程创建成功,body:", body)
if __name__ == '__main__':
create_schedule(6593, 183)
执行成功了!
D:\Python37\python.exe E:/8.pyProject/test/1.py
content: {'code': 0, 'msg': 'success', 'data': {'schedule_id': 2212}}
日程创建成功,body: {'summary': 'test', 'start_date': '2020-12-16 09:00', 'end_date': '2020-12-17 10:00', 'location': '', 'repeat_type': -1, 'remind_before_event_secs': 900, 'attendees': [{'cp_id': 154}, {'cp_id': 454}, {'cp_id': 356}], 'origin_start_date': '2020-12-16 09:00:00', 'description': ''}Process finished with exit code 0
【结论】
这是一场headers引发的xue案,费了我不少时间排查问题,而且没有头绪,瞎撞上改好了;
还是因为对http请求了解不够,学习还得再接再厉,不然BUG都找不出来~~~~