簡體   English   中英

發布多部分形式編碼的字典

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM