multipart/form-data Mirakl API 请求中的错误请求

Bad request in multipart/form-data Mirakl API request

我正尝试在 Python 3.8 中进行 API 调用。

我在curl中实现了请求,如下:

curl --location --request POST 'https://url.mirakl.net/api/orders/1720178-A/documents' --header 'Authorization: 9xxxxxxxx-4xxx-4xxx-8xxx-xxxxxxxxxxx6' --header 'Accept: application/json' --header 'Content-Type: multipart/form-data' --frm 'files=@"1720178-A.pdf"' --form 'order_documents="<body><order_documents><order_document><file_name>1720178-A.pdf</file_name><type_code>CUSTOMER_INVOICE</type_code> </order_document></order_documents></body>";type=application/xml'

有效,但 Python 代码无效:

    url = "https://url.mirakl.net/api/orders/1720178-A/documents"
    payload = {"order_documents": '<body><order_documents><order_document><file_name>1720178-A.pdf</file_name>'
                                  '<type_code>CUSTOMER_INVOICE</type_code></order_document></order_documents></body>'}
    files = [
        ("files", ('1720178-A.pdf', open('1720178-A.pdf', 'rb')))
    ]

    headers = {
        'Authorization': 'xxxxxxxxx-xxx5-4xxx-xxxx-xxxxxxxxx6',
        'Accept': 'application/json',
        'Content-Type': 'multipart/form-data'
    }

    response = requests.request("POST", url, headers=headers, data=payload, files=files)
    print(response.text)

返回以下错误:{"status":400,"message":"Bad Request"}

我在执行请求时的错误很明显,但我不知道我遗漏了什么。

我也尝试过 json 有效负载,结果相同:

payload = {"order_documents":[{"file_name":"1720178-A.pdf","type_code":"CUSTOMER_INVOICE"}]}

在我的日常工作中,我使用 Python 完成其他任务,但由于我将它用于此任务,所以我想以正确的方式完成它,而不依赖于 运行从 python.

卷曲

P.S。看了请愿书的正文,我看不出有什么不妥。

print(requests.Request("POST", url, headers=headers, files=files, data=payload).prepare().body.decode('US-ASCII', errors='ignore'))
--b54bd40f2809e798c2a04069686c35fc
Content-Disposition: form-data; name="order_documents"

{'file_name': '1720178-A.pdf', 'type_code': 'CUSTOMER_INVOICE'}
--b54bd40f2809e798c2a04069686c35fc
Content-Disposition: form-data; name="files"; filename="1720178-A.pdf"
Content-Type: application/pdf

%PDF-1.7
%
....
....
....
....
%%EOF

--b54bd40f2809e798c2a04069686c35fc--


我最近在 multipart/form 发送时遇到了类似的问题。这是我的解决方法。

我生成的 json 部分如下:

import os

data = {
            'title': (None, "testFiles", 'application/json'),
            "short": (None, "testFileShort", 'application/json'),
            "ref_name_1": (None, "TestRef2", 'application/json'),
            "upload_file_1" = (os.path.basename("test.txt"), open("test.txt", 'rb'), 'application/octet-stream')
}

我不完全确定,为什么 json 如此模糊,或者这是否是最优雅的方式,但它对我来说非常有效。

请求代码如下:

import requests

def POST(self, address, json=None, files=None):
    url = self.URL + address
    return requests.post(url=url, json=json, files=files)

try:
    r = httpBackend.POST(
        "/resources/create-files-item",
        files=data)
except Exception:
    return None

终于找到问题的根源了

为了实施 API 调用(不只是一个,而是多个),我下载了零售商向消费者提供的 Postman collection。

检查 Postman 调用是否正常后,我的失败是什么?使用软件提供的自动代码生成。虽然它是请求库的实现,但它设置了 content-type header,这会导致错误。请求正确自动生成它:

{
  "User-Agent": "sitename.app",
  "Accept-Encoding": "gzip, deflate",
  "Accept": "application/json",
  "Connection": "keep-alive",
  "Authorization": "xxx-xxxx-xxx-xxx",
  "Content-Length": "22680",
  "Content-Type": "multipart/form-data; boundary=aea8e12ea4fd0c7d9debb64f69ad0718"
}

在下面的屏幕截图中,我展示了 collection 如何包含内容类型并将其带到实现中,即使它使用请求也是如此: