2017-08-24 47 views
3

是否有機會通過API端點上傳文件,該API端點將多部分/表單數據作爲僅具有內容類型該文件的URL?如何上傳帶有多部分/表單POST的文件只有URL的文件需要上傳的文件(塊)

規則: 將整個文件下載到內存中,然後通過此端點上傳是沒有選擇的(不能保證該盒子的大小足以容納一個臨時文件)。

問題: 我想從一個服務器(GET)到另一個(multipart/form-data POST)以塊的形式傳輸文件。這可能嗎?如何實現這一目標?

流量: file_server < -GET- my_script.py -POST->上傳服務器

這裏是下載到內存(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, 
) 

答案是在像流對象創建文件的目的

非常感謝您的任何幫助。乾杯!

回答

3

如果我讀的是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, 
) 
+0

幹得漂亮!謝謝。 –