[英]Posting Multi-part form encoded dict
我正在嘗試使用第三方 API 上傳文件。 此處列出了 API 文檔: https://developers.procore.com/reference/project-folders-and-files#create-project-file
API 文檔描述了使用以下信息上傳multipart/form-data body (RFC 2388)
:
{
"file": {
"parent_id": 12,
"name": "test_file.pdf",
"is_tracked": true,
"explicit_permissions": true,
"description": "This file is good",
"data": "foobar",
"upload_uuid": "1QJ83Q56CVQR4X3C0JG7YV86F8",
"custom_field_%{custom_field_definition_id}": custom field value
}
}
我正在使用 python 請求庫,但無法使其正常工作。 我嘗試在requests.post()
中使用data={}
字段,但這不會將其作為multipart/form-data
,我嘗試使用files
字段將上面的內容作為dict
傳入但是我收到以下錯誤: TypeError: a bytes-like object is required, not 'dict'
我不知道如何讓它工作,感謝任何人可以提供的任何見解。
嘗試了什么:
sendData = {
"file": {
"parent_id":procoreDetails['destFolderId'],
"name":f.name,
"is_tracked": True,
"explicit_permissions": True,
"upload_uuid":instructions["uuid"]
}
}
r = requests.post(
headers = headers,
url = settings.API_PROC_BASE+"/vapid/files",
params={"project_id": procoreDetails['projectId']},
files=sendData
)
跟蹤錯誤:
Traceback (most recent call last):
File "./d2processor.py", line 68, in <module>
d2processor()
File "./d2processor.py", line 60, in d2processor
procoreDetails=procoreDetails
File "/mnt/gluster-vol1/Source/d2/autoAnnotate.py", line 991, in classify
files=sendData
File "/home/mnewman/envs/py36/lib/python3.6/site-packages/requests/api.py", line 119, in post
return request('post', url, data=data, json=json, **kwargs)
File "/home/mnewman/envs/py36/lib/python3.6/site-packages/requests/api.py", line 61, in request
return session.request(method=method, url=url, **kwargs)
File "/home/mnewman/envs/py36/lib/python3.6/site-packages/requests/sessions.py", line 516, in request
prep = self.prepare_request(req)
File "/home/mnewman/envs/py36/lib/python3.6/site-packages/requests/sessions.py", line 459, in prepare_request
hooks=merge_hooks(request.hooks, self.hooks),
File "/home/mnewman/envs/py36/lib/python3.6/site-packages/requests/models.py", line 317, in prepare
self.prepare_body(data, files, json)
File "/home/mnewman/envs/py36/lib/python3.6/site-packages/requests/models.py", line 505, in prepare_body
(body, content_type) = self._encode_files(files, data)
File "/home/mnewman/envs/py36/lib/python3.6/site-packages/requests/models.py", line 169, in _encode_files
body, content_type = encode_multipart_formdata(new_fields)
File "/home/mnewman/envs/py36/lib/python3.6/site-packages/urllib3/filepost.py", line 90, in encode_multipart_formdata
body.write(data)
TypeError: a bytes-like object is required, not 'dict'
這會導致以下錯誤: TypeError: a bytes-like object is required, not 'dict'
但是,這確實會強制請求使用multipart/form-data body
我也曾嘗試使用:
sendData = {
"file": {
"parent_id":procoreDetails['destFolderId'],
"name":f.name,
"is_tracked": True,
"explicit_permissions": True,
"upload_uuid":instructions["uuid"]
}
}
r = requests.post(
headers = headers,
url = settings.API_PROC_BASE+"/vapid/files",
params={"project_id": procoreDetails['projectId']},
data=sendData
)
嘗試使用data
字段發送錯誤消息:
Post to Procore: 400 - {"errors":"param is missing or the value is empty: file"}
這是上面發送的確切 header(它不執行上面 API 文檔的要求(即它使用application/x-www-form-urlencoded
而不是所需的multipart/form-data
)):
{'User-Agent': 'python-requests/2.23.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Authorization': 'Bearer <key removed>', 'Procore-Company-Id': '<removed?', 'Content-Length': '83', 'Content-Type': 'application/x-www-form-urlencoded'}
執行此請求不使用multipart/form-data
header。當我將此發送到服務器時,它報告所需的"file"
字段丟失或為空。
api 端點的文檔(上面鏈接)明確指出,上述主體結構必須作為multipart/form-data body (RFC 2388)
發送,但是我似乎無法在請求中找到執行此操作的方法。
所以解決方案是由 API 開發人員提供的,我將其發布在這里,因為它是適用於其他情況的語法細微差別。
回顧一下,問題是獲取requests
發送以下結構與multipart/form-data
header:
{
"file": {
"parent_id": 12,
"name": "test_file.pdf",
"is_tracked": true,
"explicit_permissions": true,
"description": "This file is good",
"data": "foobar",
"upload_uuid": "1QJ83Q56CVQR4X3C0JG7YV86F8",
"custom_field_%{custom_field_definition_id}": custom field value
}
}
解決方案是使用下面的代碼構建上面的結構:
sendData = {
"file[parent_id]":procoreDetails['destFolderId'],
"file[name]":fNameUpload,
}
files = [
('file[data]',open(f.filePath,'rb'))
]
r = requests.post(
headers = headers,
url = settings.API_PROC_BASE+"/vapid/files",
params={"project_id": procoreDetails['projectId']},
files=files,
data=sendData
)
請注意file[parent_id]
結構的使用,該結構允許requests
構建適當的主體嵌套dict
。 我實際上不能使用傳遞給data=
或files=
的嵌套dict
。
HTTP 數據以字符串形式發送和接收,服務器和客戶端負責按要求進行序列化和反序列化。 您收到的錯誤消息( TypeError: a bytes-like object is required, not 'dict'
)基本上意味着“你給了我一本字典,但我想要一個字符串。” (對於 ASCII 字符,Python 的字節 object 基本上是類似字符串的 object。 )
你還沒有發布你的代碼,但我懷疑它應該是這樣的:
requests.post(..., data=str(my_dict))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.