这是一个玩具,不可复制的例子,因为我不能分享原件.我认为这是有责任的,可能会对其他人有所帮助.从其他像thisthis这样的SO帖子来看,我的理解是,给定一些参数词典d,它们是等价的:

requests.post(url, data=json.dumps(d))
requests.post(url, json=d)

令牌端点的参数在文档中定义如下:

  • URL:{{base_url}}/Token
  • 参数
      • Grand_type=\\密码/LI>
      • 用户名=__用户名/LI>
      • Password=\\Password/LI>
      • 范围={"Account":"__Account+","Tenant":"__Tenant抯/Li>

我从这个开始,从.env文件加载变量:

resp = requests.post(f'{base_url}/token',
                     json={'grant_type': 'password', 'username': uname, 'password': pwd,
                           'scope': {'account': account, 'tenant': tenant}})
resp.text
# '{"error":"unsupported_grant_type"}'

我try 更改为data参数,得到了一个更合理的错误:

resp = requests.post(f'{base_url}/token',
                     data={'grant_type': 'password', 'username': uname, 'password': pwd,
                           'scope': {'account': account, 'tenant': tenant}})
resp.text
# '{"error":"invalid_grant","error_description":"{\\"ErrorMessage\\":\\"Error trying to Login  - User [username] Account [] Unexpected character encountered while parsing value: a.

我try 了其他一些方法,比如用引号将arg括起来(例如{'account': f"{account}"}),但没有成功,最终用这个"混合"方法成功了:

resp = requests.post(f'{base_url}/token',
                 data={'grant_type': 'password', 'username': uname, 'password': pwd,
                       'scope': json.dumps({'account': account, 'tenant': tenant})})

我的问题:

  • 这种细微差别是"真实的"还是直接阅读相关问题?也就是说,看起来either使用data=json.dumps(d)json=d,但我还没有找到混合这两者的答案(将整个data arg包装在json.dumps()中打破了我正在工作的最终版本)
  • 作为API/网络领域的新手,我能从上面列出的文档论证中看出这一点吗,或者试错是发现这一点的唯一方法吗?
  • 给出我的最终解决方案,有没有更好/更正确的方式来传递这些参数?

推荐答案

提供json=data=个论点有很大的区别.

提供json=将发送Content-Type: application/json,并将您发送的数据格式化为json-字符串.例如,以下请求:

resp = requests.post(url, json={"a": 42, "b": 55})

将导致服务器收到以下消息:

POST / HTTP/1.1
Host: localhost:12001
User-Agent: python-requests/2.28.1
Accept-Encoding: gzip, deflate, br
Accept: */*
Connection: keep-alive
Content-Length: 18
Content-Type: application/json


{"a": 42, "b": 55}

而发送与数据相同的数据将作为内容类型为application/x-www-form-urlencoded的表单数据发送:

resp = requests.post(url, data={"a": 42, "b": 55})

将导致服务器收到以下消息:

POST / HTTP/1.1
Host: localhost:12001
User-Agent: python-requests/2.28.1
Accept-Encoding: gzip, deflate, br
Accept: */*
Connection: keep-alive
Content-Length: 9
Content-Type: application/x-www-form-urlencoded


a=42&b=55

如果您使用的是data=json.dumps(...)版本,则实质上是将单个字符串作为数据进行传递.字符串是json格式的,但是请求不知道这一点(它可以是任何东西).在这种情况下,请求似乎不发送任何Content-Type,您必须在代码中显式设置它.

现在,哪个变体是正确的取决于您正在使用的API,但是由于数据似乎是 struct 化的,所以不能很好地编码成表单数据,所以可能json是您想要发送的.

对于混合解决方案,我认为它表明API的设计非常糟糕,但以下是服务器接收的内容:

POST / HTTP/1.1
Host: localhost:12001
User-Agent: python-requests/2.28.1
Accept-Encoding: gzip, deflate, br
Accept: */*
Connection: keep-alive
Content-Length: 145
Content-Type: application/x-www-form-urlencoded


grant_type=password&username=treuss&password=s3cret&scope=%7B%22account%22%3A+%22treuss%40stackoverflow.com%22%2C+%22tenant%22%3A+%22tenant%22%7D

scope=之后的所有内容都是从本例中的json.dump生成的编码json字符串,即字符串{"account": "treuss@stackoverflow.com", "tenant": "tenant"}的url编码版本.

Python相关问答推荐

为什么Pydantic在我申报邮箱时说邮箱丢失

日程优化问题不知道更好的方式来呈现解决方案- Python / Gekko

带有计数值的Pandas数据帧

OdooElectron 商务产品详情页面中add_qty参数动态更新

如何以实现以下所述的预期行为的方式添加两只Pandas pyramme

如何将自动创建的代码转换为类而不是字符串?

Python中的锁定类和线程以实现dict移动

CustomTKinter-向表单添加额外的输入字段

保留包含pandas pandras中文本的列

如何将不同长度的新列添加到现有的框架中

如何观察cv2.erode()的中间过程?

Python主进程和分支进程如何共享gc信息?

从管道将Python应用程序部署到Azure Web应用程序,不包括需求包

GL pygame无法让缓冲区与vertextPointer和colorPointer一起可靠地工作

如何比较numPy数组中的两个图像以获取它们不同的像素

如何从数据库上传数据到html?

使用Python从URL下载Excel文件

如何在TensorFlow中分类多个类

如何在PySide/Qt QColumbnView中删除列

为什么if2/if3会提供两种不同的输出?