@azaya

Загрузка файла на сервере при лимите на размер тела запроса?

Привет, столкнулся с проблемой отправки файлов на файловый хостинг. Владельцы сайта ограничили размер для тела запроса. В 1 варианте, я просто загружаю файл, если его размер будет меньше размера допустимого чанка, сервер вернет ответ в виде json, иначе ошибку 413 Client Error: Request Entity Too Large
В 2 варианте, я загружаю файл почанково, но скрипт загружает каждый чанк, как уникальный, что выглядит логично, в виду того, что в цикле я инициирую новые инстансы энкодера.
В 3 варианте, я из энкодера беру определенное количесто байт и пытаюсь загрузить их, но сервер возвращает ошибку 500 Server Error: Internal Server Error
Что я делаю не так? Спасибо за помощь.

Вариант 1
import requests
from requests_toolbelt import MultipartEncoder
from os.path import basename, getsize, abspath
from argparse import ArgumentParser
from pprint import pprint
from math import ceil


BASE_URL = 'https://s3.krakenfiles.com/_uploader/gallery/upload'

CHUNK_SIZE = 20000000


def uploader(file_path):

    session = requests.Session()
    session.options(BASE_URL)

    FILE_NAME = basename(file_path)

    encoder = MultipartEncoder(
        fields={'files[]': (FILE_NAME, open(file_path, 'rb'))}
    )

    response = session.post(
        BASE_URL,
        data=encoder,
        headers={'Content-Type': encoder.content_type}
    )

    response.raise_for_status()
    pprint(response.content)

if __name__ == '__main__':
    parser = ArgumentParser()
    parser.add_argument(
        '-p', '--path',
        dest='file_path'
    )
    args = parser.parse_args()

    file_path = args.file_path

    if file_path:
        uploader(abspath(file_path))


Вариант 2
import requests
from requests_toolbelt import MultipartEncoder
from os.path import basename, getsize, abspath
from argparse import ArgumentParser
from pprint import pprint
from math import ceil


BASE_URL = 'https://s3.krakenfiles.com/_uploader/gallery/upload'

CHUNK_SIZE = 20000000


def uploader(file_path):

    session = requests.Session()
    session.options(BASE_URL)

    FILE_NAME = basename(file_path)
    FILE_SIZE = getsize(file_path)
    CHUNK_COUNT = ceil(FILE_SIZE / CHUNK_SIZE)

    for i in range(CHUNK_COUNT):
        offset = CHUNK_SIZE * i
        bytes = min(CHUNK_SIZE, FILE_SIZE - offset)

        encoder = MultipartEncoder(
            fields={'files[]': (FILE_NAME, open(file_path, 'rb').read(bytes))}
        )

        response = session.post(
            BASE_URL,
            data=encoder,
            headers={'Content-Type': encoder.content_type}
        )

        response.raise_for_status()
        pprint(response.content)


if __name__ == '__main__':
    parser = ArgumentParser()
    parser.add_argument(
        '-p', '--path',
        dest='file_path'
    )
    args = parser.parse_args()

    file_path = args.file_path

    if file_path:
        uploader(abspath(file_path))

Вариант 3
import requests
from requests_toolbelt import MultipartEncoder
from os.path import basename, getsize, abspath
from argparse import ArgumentParser
from pprint import pprint
from math import ceil


BASE_URL = 'https://s3.krakenfiles.com/_uploader/gallery/upload'

CHUNK_SIZE = 20000000


def uploader(file_path):

    session = requests.Session()
    session.options(BASE_URL)

    FILE_NAME = basename(file_path)
    FILE_SIZE = getsize(file_path)
    CHUNK_COUNT = ceil(FILE_SIZE / CHUNK_SIZE)

    encoder = MultipartEncoder(
        fields={'files[]': (FILE_NAME, open(file_path, 'rb'))}
    )

    for i in range(CHUNK_COUNT):
        offset = CHUNK_SIZE * i
        bytes = min(CHUNK_SIZE, FILE_SIZE - offset)

        response = session.post(
            BASE_URL,
            data=encoder.read(bytes),
            headers={'Content-Type': encoder.content_type}
        )

        response.raise_for_status()
        pprint(response.content)


if __name__ == '__main__':
    parser = ArgumentParser()
    parser.add_argument(
        '-p', '--path',
        dest='file_path'
    )
    args = parser.parse_args()

    file_path = args.file_path

    if file_path:
        uploader(abspath(file_path))
  • Вопрос задан
  • 232 просмотра
Решения вопроса 1
@azaya Автор вопроса
Решение
import requests
from requests_toolbelt import MultipartEncoder
from os.path import basename, getsize, abspath
from argparse import ArgumentParser
from math import ceil

from json.decoder import JSONDecodeError


BASE_URL = 'https://s3.krakenfiles.com/_uploader/gallery/upload'

MAX_CHUNK_SIZE = 1024 * 1024 * 70


def uploader(file_path):

    FILE_NAME = basename(file_path)
    FILE_SIZE = getsize(file_path)

    session = requests.Session()
    session.options(BASE_URL)

    session.headers.update({
      'Content-Disposition': (
        f'form-data; name="files[]"; filename="{ FILE_NAME }"'
      )
    })

    CHUNK_COUNT = ceil(FILE_SIZE / MAX_CHUNK_SIZE)

    with open(file_path, 'rb') as f:

        for i in range(CHUNK_COUNT):
            offset = MAX_CHUNK_SIZE * i
            chunk_size = min(MAX_CHUNK_SIZE, FILE_SIZE - offset)

            encoder = MultipartEncoder(
                fields={'files[]': (FILE_NAME, f.read(chunk_size))}
            )

            session.headers.update({
              'Content-Length': str(encoder.len),
              'Content-Range': f'bytes { offset }-{ (offset + chunk_size) - 1 }/{ FILE_SIZE }',
              'Content-Type': encoder.content_type
            })

            response = session.post(
                BASE_URL,
                data=encoder
            )

            try:
                data = response.json()
                if not data:
                    continue
            except JSONDecodeError:
                pass

            files = data.get('files', [])

            if not files:
                return False

            file = files[0]

            error = file.get('error')
            purl = file.get('url')

            if error:
                return error

            return f'https://krakenfiles.com{ purl }'

    return False

if __name__ == '__main__':
    parser = ArgumentParser()
    parser.add_argument(
        '-p', '--path',
        dest='file_path'
    )
    args = parser.parse_args()

    file_path = args.file_path

    if file_path:
        print(uploader(abspath(file_path)))
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
tumbler
@tumbler Куратор тега Python
бекенд-разработчик на python
Вы пытаетесь загрузить файл больше лимита. Вряд ли это получится, если этого не хотят владельцы файлового хостинга.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы