使用python请求库将文件发布到服务器时出现错误的请求错误

时间:2019-07-06 07:26:22

标签: python python-3.x python-requests

当我尝试使用python请求库将文件发布到服务器时,出现HTTP代码400(错误请求)。

相应的curl请求成功:

curl -X POST -i https://de.api.labs.sophos.com/analysis/file/static/v1 \
-H 'Authorization: auth_string' \
-H 'Content-Type: multipart/form-data' \
-F "file=@filename"

API文档:https://api.labs.sophos.com/doc/analysis/file/static.html

有人可以帮我解决我可能做错的事情吗?
到目前为止,我的代码:

import requests

url = "https://de.api.labs.sophos.com/analysis/file/static/v1"
headers = {'content-type': 'multipart/form-data', 'Authorization': authorization}

with open(filepath, 'rb') as f:      
    files = {'file': f}  # Even tried {'file': f.read()}
    r = requests.post(url, files=files, headers=headers)
    if r.status_code in [200, 202]:
        return r.json()
    else:
        return r

1 个答案:

答案 0 :(得分:1)

TL; DR

尝试通过这种方式做到这一点:

import requests

url = "https://de.api.labs.sophos.com/analysis/file/static/v1"
headers = {'Authorization': authorization}  # no Content-Type here

r = requests.post(url, headers=headers, files={"file": open(filepath, "rb")})
print(r.status_code, r.text)

为什么

posting filesContent-Type一起使用时,您不应该手动设置requests标头。

原因有两个:

  • requests将在发出实际的HTTP请求之前隐式将Content-Type设置为multipart/form-data(例如,对Content-Length而言)
  • 使用Content-Type: multipart/form-data时,还应指定一个boundary。如果未设置边界,则服务器将无法正确地从请求主体读取数据。因此,如果您使用Content-Type,则边界是multipart/form-data标头的必需部分

在您的示例中,您没有为请求设置边界。事实是requests 不会为您设置(如果您覆盖Content-Type标头(您这样做)。然后服务器无法在请求正文中读取您的文件。因此,它将返回您400 Bad Request

发出请求后,可以通过键入print(r.request.headers["Content-Type"])进行检查。它将输出以下内容:

multipart/form-data

,但必须看起来像这样:

multipart/form-data; boundary=6387a52fb4d1465310a2b63b2d1c6e70

另一方面,curl 隐式添加边界,因此您一切都很好,您会收到200 OK

您也可以检查它:

curl -H 'Content-Type: multipart/form-data' -F "file=@123.txt" -v http://httpbin.org/post

哪个输出:

* Connected to httpbin.org (34.230.136.58) port 80 (#0)
> POST /post HTTP/1.1
> Host: httpbin.org
> User-Agent: curl/7.47.0
> Content-Type: multipart/form-data; boundary=------------------------d257f5f4377a3997
...