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

Dev*_*ain 3 python python-3.x python-requests

当我尝试使用 python requests 库将文件发布到服务器时,我收到 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"
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

Iva*_*dov 5

长话短说

尝试这样做:

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)
Run Code Online (Sandbox Code Playgroud)

为什么

发布文件时不应Content-Type手动设置标题。requests

原因有两个:

  • requests将在发出实际的 HTTP 请求之前隐式设置Content-Type为(例如)multipart/form-dataContent-Length
  • 使用时还Content-Type: multipart/form-data应该指定边界。如果没有设置边界,服务器将无法正确从请求体中读取数据。因此,如果您使用.Content-Typemultipart/form-data

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

print(r.request.headers["Content-Type"])您可以在提出请求后通过输入进行检查。它将输出这个:

multipart/form-data
Run Code Online (Sandbox Code Playgroud)

,但它必须看起来像这样:

multipart/form-data; boundary=6387a52fb4d1465310a2b63b2d1c6e70
Run Code Online (Sandbox Code Playgroud)

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

您也可以检查一下:

curl -H 'Content-Type: multipart/form-data' -F "file=@123.txt" -v http://httpbin.org/post
Run Code Online (Sandbox Code Playgroud)

哪个输出:

* 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
...
Run Code Online (Sandbox Code Playgroud)