【问题标题】:How to upload file with multipart/form POST having only URL to file that need to be uploaded (chunks) [duplicate]如何使用 multipart/form POST 上传文件,该文件只有需要上传的文件的 URL(块)[重复]
【发布时间】:2018-02-02 10:01:12
【问题描述】:

是否有机会通过 API 端点上传文件,该端点将 multipart/form-data 作为仅具有该文件 URL 的内容类型?

规则: 将整个文件下载到内存中,然后通过此端点上传是不可行的(无法保证该框将足够大以容纳临时文件)。

问题: 我想将文件分块从一台服务器(GET)流式传输到另一台服务器(multipart/form-data POST)。这可能吗?如何实现?

流程: file_server 上传服务器

这是一个下载到内存 (RAM) 选项的简单示例(但它违反了规则):

from io import BytesIO

import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder

file_url = 'https://www.sysaid.com/wp-content/uploads/features/itam/image-banner-asset.png'
requested_file_response = requests.get(file_url, stream=True)

TOKEN_PAYLOAD = {
    'grant_type': 'password',
    'client_id': '#########',
    'client_secret': '#########',
    'username': '#########',
    'password': '#########'
}


def get_token():
    response = requests.post(
        'https://upload_server/oauth/token',
        params=TOKEN_PAYLOAD)
    response_data = response.json()
    token = response_data.get('access_token')
    if not token:
        print("token error!")
    return token

token = get_token()

file_object = BytesIO()
file_object.write(requested_file_response.content)

# Form conctent
multipart_data = MultipartEncoder(
    fields={
        '--': (
            'test.png',
            file_object  # AttributeError: 'generator' object has no attribute 'encode' when I try to pass generator here.
        ),  
        'id': '2217',
        'fileFieldDefId': '4258',
    }
)

# Create headers
headers = {
    "Authorization": "Bearer {}".format(token),
    'Content-Type': multipart_data.content_type
}

session = requests.Session()
response = session.post(
    'https://upload_server/multipartUpdate',
    headers=headers,
    data=multipart_data,
)

答案在一个文件中,比如为流目的创建对象

非常感谢您的帮助。干杯!

【问题讨论】:

    标签: python post file-upload python-3.5 multipartform-data


    【解决方案1】:

    如果我正确阅读了requests_toolbelt 源代码,那么它不仅需要.read() 文件的能力(我们可以通过传递requests.get(..., stream=True).raw 来获得),而且还需要某种方式来确定有多少数据留在流中。

    假设你确信你总是有一个有效的 content-length 标头,这将是我建议的解决方案:

    import requests
    from requests_toolbelt.multipart.encoder import MultipartEncoder
    
    file_url = 'https://www.sysaid.com/wp-content/uploads/features/itam/image-banner-asset.png'
    target = 'http://localhost:5000/test'
    
    
    class PinocchioFile:
        """I wish I was a real file"""
    
        def __init__(self, url):
            self.req = requests.get(url, stream=True)
            length = self.req.headers.get('content-length')
            self.len = None if length is None else int(length)
            self._raw = self.req.raw
    
        def read(self, chunk_size):
            chunk = self._raw.read(chunk_size) or b''
            self.len -= len(chunk)
            if not chunk:
                self.len = 0
            return chunk
    
    
    multipart_data = MultipartEncoder(
        fields={
            '--': (
                'test.png',
                PinocchioFile(file_url),
            ),
            'id': '2217',
            'fileFieldDefId': '4258',
        }
    )
    
    # Create headers
    headers = {
        'Content-Type': multipart_data.content_type
    }
    
    response = requests.post(
        target,
        data=multipart_data,
        headers=headers,
    )
    

    【讨论】:

    • 干得好!谢谢。
    猜你喜欢
    • 2014-12-27
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 2015-10-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多