如何用Python发送x-www-form-urlencoded格式的PATCH请求?
问题描述
向Zulip接口发送PATCH请求编辑草稿时,返回Missing 'draft' argument错误。现有代码如下:
draft_content = body_serializer.data['content'] recipient_stream_id = user_to.zulip_id topic = "draft" draft_type = "private" data = {"draft" : { "content": draft_content, "to": [recipient_stream_id], "topic": topic, "type": draft_type }} try: response = requests.patch( f'{settings.ZULIP_SITE}api/v1/drafts/{draft_id}', headers={'Content-Type': 'application/x-www-form-urlencoded'}, json=urlencode(data), auth=(user.zulip_email, user.zulip_api_key), verify=False ) result = response.json() # 将JSON响应转为字典 except Exception as err: return Response( {'message': f'Error editing draft: {err}'}, status=status.HTTP_404_NOT_FOUND, ) if result["result"] == 'error': return Response( {'message': result}, status=status.HTTP_404_NOT_FOUND ) elif result["result"] == 'success': response_data = ZulipEditDraftResponse( data={ 'result': str(result["result"]), } )
返回的错误信息:
{ "message": { "result": "error", "msg": "Missing 'draft' argument", "var_name":"draft", "code":"REQUEST_VARIABLE_MISSING" } }
使用Postman测试时,最初选raw请求体类型也报错,改为x-www-form-urlencoded后请求成功,对应的curl命令:
curl --location --request PATCH 'http://api.pets.kruts.net/api/v1/zulip/draft/edit/2/' \ --header 'Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjkyMDkzMzM5LCJqdGkiOiJjY2ZlZmNkMmJhNWY0ZWZiYWRlY2Y1ZGQ3NzA3NTMyNSIsInVzZXJfaWQiOjg0OX0.rk4vSSQ_LVT3OQFXuFW21pg1FacKhgRLOHYWdprCnDY' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'email_to=+380635990523@mail.com' \ --data-urlencode 'content=helooo'
已尝试json.dumps和urlencode方法,但问题仍未解决,求Python中正确的请求实现方式。
解决方案
错误原因
代码存在两个核心问题:
- 错误使用
json参数传递表单数据:json参数会自动将内容序列化为JSON格式并设置Content-Type为application/json,和手动设置的x-www-form-urlencoded头部冲突,导致接口无法识别参数。 - 未正确处理嵌套字典的表单编码:
urlencode无法直接解析嵌套字典结构,需要将draft下的子参数转为draft[xxx]格式的扁平键值对。
修正后的代码
draft_content = body_serializer.data['content'] recipient_stream_id = user_to.zulip_id topic = "draft" draft_type = "private" # 将嵌套的draft结构转为表单要求的键值对格式 form_data = { 'draft[content]': draft_content, 'draft[to][]': recipient_stream_id, # 数组类型参数需用[]后缀 'draft[topic]': topic, 'draft[type]': draft_type } try: response = requests.patch( f'{settings.ZULIP_SITE}api/v1/drafts/{draft_id}', # 无需手动设置Content-Type,使用data参数时requests会自动处理 data=form_data, auth=(user.zulip_email, user.zulip_api_key), verify=False ) result = response.json() except Exception as err: return Response( {'message': f'Error editing draft: {err}'}, status=status.HTTP_404_NOT_FOUND, ) if result["result"] == 'error': return Response( {'message': result}, status=status.HTTP_404_NOT_FOUND ) elif result["result"] == 'success': response_data = ZulipEditDraftResponse( data={ 'result': str(result["result"]), } )
关键说明
- 参数传递方式:改用
data参数传递表单数据,requests会自动完成x-www-form-urlencoded编码,并设置正确的请求头,无需手动指定Content-Type。 - 嵌套参数处理:Zulip的表单接口要求嵌套参数以
draft[xxx]格式传递,数组类型参数需添加[]后缀(如draft[to][]),如果有多个收件ID,可重复添加该键传递多个值。 - 避免手动编码:直接传递字典给
data参数即可,requests会自动调用urlencode完成编码,无需手动处理后再传给json参数。
内容的提问来源于stack exchange,提问作者Andreww_xian
相关产品推荐
相关产品推荐

