Flask: проблема с возвратом двоичного файла клиенту - PullRequest
0 голосов
/ 15 февраля 2020

Я загружаю архив с Github и хочу вернуть его в браузер для загрузки. Я успешно получил файл и могу сохранить его на локальном диске c (я могу открыть архив и он нормальный - размер и содержимое):

headers = {'Authorization': 'token ' + github_token}
zip_response = requests.get(github_url, headers = headers)

output = open("archive.zip", "wb")
output.write(zip_response.content)
output.close()

Но когда я возвращаю его клиенту, он больше почти в два раза, и архив поврежден:

zip_content = io.BytesIO(zip_response.content)
return send_file(zip_content, 
                 mimetype='application/zip', 
                 attachment_filename = 'archive.zip')

Javascript:

var url = window.URL.createObjectURL(new Blob([response.data]), {type: 'application/zip'});
var link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'archive.zip');
document.body.appendChild(link);
link.click();

Я пытался использовать другие решения этой проблемы: Загрузить файл из байтов в JavaScript

, но ничего не работает.

Это просто возвращает 0 байтов:

var bytes = new Uint8Array(response.data)

Это вызывает исключение "Не удалось выполнить 'atob' в" Окне " ': Строка для декодирования содержит символы вне диапазона Latin1. ":

var binaryString = window.atob(response.data);

Upd: я обнаружил, что response.data имеет нормальную длину, но когда я создаю новый объект Blob, его в 2 раза больше, Я не знаю почему.

1 Ответ

0 голосов
/ 16 февраля 2020

Вы не показываете нам, как вы получаете ваш response.data, но я предполагаю, что вы не устанавливаете свойство responseType вашего объекта xhr (или вы полагаетесь на старый XMLHttpRequest).

Вот полный рабочий пример (протестирован в последних Firefox и Chrome) на основе вашего кода:

import io
from flask import Flask, send_file

app = Flask(__name__)

@app.route('/')
def home():
    return  """
<!doctype html>
<html>
<head>
<script>
function getZip() {
       var xhr = new XMLHttpRequest();
       xhr.responseType = 'blob'
       xhr.open('GET', '/sampleZip');
       xhr.onload = function(e) {
           if (this.status == 200) {
              var blob = new Blob([this.response], {type: 'application/zip'});
              var url = window.URL.createObjectURL(blob);
              var link = document.createElement('a');
              link.href = url;
              link.setAttribute('download', 'archive.zip');
              document.body.appendChild(link);
              link.click();
           }
       };
       xhr.send();
       return false;
}
</script>
</head>
<body>
  <button id="btn" onclick="getZip();">Click Me</button>
</body>
</html>"""


@app.route('/sampleZip')
def sampleZip():
    with open("sample.zip", "rb") as f:
        bytes = io.BytesIO(f.read())
    return send_file(bytes, mimetype='application/zip')

Если вы застряли, полагаясь на старый объект XMLHttpRequest, то вы можете захотеть чтобы посмотреть (https://www.html5rocks.com/en/tutorials/file/xhr2/), как взломать XHR старой школы для обработки данных как двоичных и оставить их нетронутыми.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...