Сохранение файла из BLOB-объекта: http с использованием JavaScript без перенаправления - PullRequest
0 голосов
/ 05 февраля 2019

Я уже прошел через некоторые из предлагаемых решений здесь, в SO, но безуспешно.Это проблема.Когда большой двоичный объект генерируется с использованием данных, полученных из конечной точки API, я хочу заставить браузер загрузить большой двоичный объект.Пока я пробовал три решения, но ни одно из них не работает.Кодекс следует.Обратите внимание, что я добавил несколько комментариев в код, чтобы объяснить это дальше.

const FILE_NAME_REGEX = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
    
    export function Download(url) {
    	return APICall.get(url).then(response => {
    		const disposition = response.request.getResponseHeader('Content-Disposition');
    		//^This line gives the 'Refused to get unsafe header "Content-Disposition"' error, so next few lines won't execute and part with generating anchor is not used, but the part of code under the 'else' branch.
    
    		if (disposition && disposition.indexOf('attachment') !== -1) {
    			const matches = FILE_NAME_REGEX.exec(disposition);
    
    			if (matches != null && matches[1]) {
    				filename = matches[1].replace(/['"]/g, '');
    			}
    		}
    
    		const type = response.request.getResponseHeader('Content-Type');
    
    		const blob = new Blob([response.data], { type });
    
    		if (typeof window.navigator.msSaveBlob !== 'undefined') {
    			window.navigator.msSaveBlob(blob, filename);
    		} else {
    			const URL = window.URL || window.webkitURL;
    			const downloadUrl = URL.createObjectURL(blob);
    
    			if (filename) {
    				const a = document.createElement('a');
    
    				if (typeof a.download === 'undefined') {
    					window.location = downloadUrl;
    				} else {
    					a.href = downloadUrl;
    					a.download = filename;
    					document.body.appendChild(a);
    					a.click();
    					document.body.removeChild(a);
    				}
    			} else {

 // 1. soultion 
   window.location = downloadUrl;

 }
    
    			setTimeout(() => {
    				URL.revokeObjectURL(downloadUrl);
    			}, 100);
    		}
    	});
    }

// 2. решение

        const ifrmDownloader = document.createElement('iframe');
        ifrmDownloader.setAttribute('src', downloadUrl);
        ifrmDownloader.style.width = '0px';
        ifrmDownloader.style.height = '0px';
        document.body.appendChild(ifrmDownloader);

// 3. решение

window.open(downloadUrl,_blank);
  1. Решениене работает, потому что он открывает другую вкладку и возвращает пустой квадрат вместо файла.Это, вероятно, связано с потерей временного блоба при открытии новой вкладки.

  2. Решение просто не работает, и я не знаю почему.Iframe добавляется в dom и запрос записывается на вкладке Network в консоли разработчика, но загрузка не инициируется.Вероятно, причина та же, что и в решении 1. Кроме того, это сообщение заносится в журнал:

Ресурс интерпретируется как Документ, но передается с MIME-типом image / png: "blob: https://example.com/e53bf47b-7f39-4758-b3dd-3cc2df5889ad".

Решение не работает так же хорошо.Во-первых, всплывающее окно заблокировано браузером, и после того, как оно разрешено, загрузка файла не начинается.

Я чувствую, что здесь чего-то не хватает, но что?

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

Вот то, что я нашел в отношении проблемы, которую я разместил.На самом деле были две проблемы:

  1. Заголовок Content-Disposition получал отказ, и поэтому ни имя файла, ни информация об удалении не были доступны.В соответствии с ответом @ Kaiido это было преодолено путем извлечения имени файла из URL и добавления ', png'.EG

    const chunks = extendedURl.split('/');
    const pngExtension = '.png';
    const baseName = chunks[chunks.length - 1].split('?')[0];
    filename = `${baseName}${pngExtension}`;
    
  2. Более серьезная проблема, которую я не осознавал до сегодняшнего дня, заключалась в том, что когда вызывался метод axios Get , responseType былне установлен в ' arraybuffer '.

    Таким образом, я смог загрузить файлы, которые были «повреждены».Этот вопрос помог мне выяснить, где была настоящая проблема: Файл поврежден при загрузке с использованием углового $ http

После вызова метода Get был предоставлен ' responseType: "arraybuffer"", файлы начали казаться нормальными, а не" битыми ".

Подводя итог, при вызове конечной точки .net Core Web API, которая возвращает FileStreamResult , чтобы иметь возможность создавать Blob в вашем FE JavaScript, вы должныявным образом установите responseType в 'arraybuffer' следующим образом:

axios.get(extendedURl, { responseType: 'arraybuffer' }).then(response =>...
0 голосов
/ 06 февраля 2019

Ваш код настроен для загрузки файла, только если установлена ​​переменная filename.

Эта переменная устанавливается только тогда, когда вы можете прочитать заголовок Content-Disposition (т. Е. Только при том же происхождении).

Таким образом, простым решением было бы установить фиктивное значение для filename, когда вам не удалось получить его из заголовков, таким образом, filename всегда установлено, и вы всегда пытаетесь загрузить его вместопросто открыв его на новой странице.
Самое разумное исправление - попытаться разобрать имя файла из переменной url, но без знания формата возможных URL-адресов сложно создать его для вас.

const FILE_NAME_REGEX = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;

export function Download(url) {
  return APICall.get(url).then(response => {
      const disposition = response.request.getResponseHeader('Content-Disposition');
      if (disposition && disposition.indexOf('attachment') !== -1) {
        const matches = FILE_NAME_REGEX.exec(disposition);

        if (matches != null && matches[1]) {
          filename = matches[1].replace(/['"]/g, '');
        }
      }
      if (!filename) {
        // getFileNameFromURL(url);
        filename = 'dummy.png';
      }
      const type = response.request.getResponseHeader('Content-Type');

      const blob = new Blob([response.data], {
        type
      });

      if (typeof window.navigator.msSaveBlob !== 'undefined') {
        window.navigator.msSaveBlob(blob, filename);
      } else {
        const URL = window.URL || window.webkitURL;
        const downloadUrl = URL.createObjectURL(blob);

//     if (filename) { // always truthy
        const a = document.createElement('a');

        if (typeof a.download === 'undefined') {
          window.location = downloadUrl;
        } else {
          a.href = downloadUrl;
          a.download = filename;
          document.body.appendChild(a);
          a.click();
          document.body.removeChild(a);
        }
//    }
/*  else { // useless
    window.location = downloadUrl;
    }
*/
      setTimeout(() => {
        URL.revokeObjectURL(downloadUrl);
      }, 100);
    }
  });
}
...