小能豆

将标头信息 PUT 到 Webdav 服务器时写入文件

py

我有以下代码:

    r = requests.put(
        config.get('webdav', 'url') + file_name,
        auth=(
            config.get('webdav', 'username'),
            config.get('webdav', 'password')
        ),
        files={
            "files": open(os.path.expanduser(charges_file_path), 'rb')
        }
    )

这相当简单。它只是PUT向 webdav 服务器发出请求,并将文件中的数据(纯文本)推送到服务器。

它能正常工作,除了一个奇怪的问题(或者如果我只是忽略了一些小问题,可能就不那么奇怪了)。当我GET对文件执行操作时,或者直接在服务器上查看文件时,文件本身包含标头信息:

–55e72d74a10b423590cd4faa68212192 内容处置:表单数据;名称=“文件”;文件名=“test_file6.txt”

(文件数据)

–55e72d74a10b423590cd4faa68212192–

我还没能找到原因或解决方法。当我从命令行 cURL 文件时,它工作正常。

有什么想法吗?


阅读 27

收藏
2024-12-26

共1个答案

小能豆

这个问题通常发生在你上传文件时,requests 库默认会使用 multipart/form-data 来发送文件,而 PUT 请求通常不需要这些额外的表单标头。multipart/form-data 格式包含 Content-Disposition 标头,它指定了文件上传的元数据(例如文件名)。而你在服务器端获取的文件中显示了这些表单标头,可能是由于请求的内容类型或文件上传方式不符合你的预期。

解决方法

你希望文件直接作为纯文本上传,而不是通过表单数据上传,因此你不应该将文件包裹在 files 字段中,这会导致 requests 使用 multipart/form-data。相反,应该以字节流的形式上传文件。你可以通过以下方法修改代码:

方法 1:直接上传文件内容(避免 multipart/form-data

import requests
import os
from configparser import ConfigParser

# 配置文件
config = ConfigParser()
config.read('config.ini')

# 读取文件路径
charges_file_path = '/path/to/your/file.txt'
file_name = 'test_file6.txt'

# 打开文件并将其内容直接发送
with open(os.path.expanduser(charges_file_path), 'rb') as file_data:
    r = requests.put(
        config.get('webdav', 'url') + file_name,
        auth=(
            config.get('webdav', 'username'),
            config.get('webdav', 'password')
        ),
        data=file_data  # 使用data而不是files
    )

print(r.status_code)

在这个方法中,文件内容被直接发送到 PUT 请求的正文中,而不使用 files 字段,这样就避免了 Content-Type: multipart/form-data 和额外的标头。data=file_data 会将文件作为原始字节流上传,WebDAV 服务器应该接收并存储这个文件,而不再包含表单标头。

方法 2:检查 Content-Type(如果需要)

如果你仍然希望使用 files 字段上传文件(通常是处理文件上传时使用),你可以显式地设置 Content-Type,以避免 requests 自动生成 multipart/form-data 类型。

import requests
import os
from configparser import ConfigParser

# 配置文件
config = ConfigParser()
config.read('config.ini')

# 读取文件路径
charges_file_path = '/path/to/your/file.txt'
file_name = 'test_file6.txt'

# 打开文件并设置适当的 Content-Type
with open(os.path.expanduser(charges_file_path), 'rb') as file_data:
    headers = {
        'Content-Type': 'application/octet-stream',  # 你可以根据需要选择合适的内容类型
    }
    r = requests.put(
        config.get('webdav', 'url') + file_name,
        auth=(
            config.get('webdav', 'username'),
            config.get('webdav', 'password')
        ),
        data=file_data,
        headers=headers
    )

print(r.status_code)

通过手动设置 Content-Typeapplication/octet-stream 或其他合适的 MIME 类型,你可以避免 requests 自动使用 multipart/form-data

总结

  • 方法 1:最简单的方法是直接使用 data=file_data,而不是使用 files,从而避免 requests 自动将文件包装成 multipart/form-data
  • 方法 2:如果你仍然希望使用 files,则显式地设置 Content-Type,避免它默认使用 multipart/form-data

通过这些修改,你应该能够避免在文件内容中看到额外的表单标头。

2024-12-26