Як завантажувати файли за допомогою axios


124

Я використовую axios для основних http-запитів, таких як GET та POST, і це працює добре. Тепер мені також потрібно завантажити файли Excel. Чи можливо це з аксіями? Якщо так, чи є у когось якийсь зразок коду? Якщо ні, що ще я можу використовувати в програмі React, щоб зробити те саме?


Ми можемо використовувати це рішення для завантаження файлу Excel. stackoverflow.com/questions/57127361/…
Md. Nazrul Islam

Відповіді:


107

Коли відповідь приходить із завантажуваним файлом, заголовки відповідей будуть приблизно такими

Content-Disposition: "attachment;filename=report.xls"
Content-Type: "application/octet-stream" // or Content-type: "application/vnd.ms-excel"

Що ви можете зробити, це створити окремий компонент, який міститиме приховану рамку.

  import * as React from 'react';

  var MyIframe = React.createClass({

     render: function() {
         return (
           <div style={{display: 'none'}}>
               <iframe src={this.props.iframeSrc} />
           </div>
         );
     }
  });

Тепер ви можете передати URL-адресу завантажуваного файлу як prop цьому компоненту, тому, коли цей компонент отримає prop, він буде повторно відтворений і файл буде завантажений.

Редагувати: Ви також можете використовувати модуль для завантаження js-файлів . Посилання на репозиторій Github

const FileDownload = require('js-file-download');

Axios({
  url: 'http://localhost/downloadFile',
  method: 'GET',
  responseType: 'blob', // Important
}).then((response) => {
    FileDownload(response.data, 'report.csv');
});

Сподіваюся, це допомагає :)


1
Дякую. Чи можете ви сказати мені, чи це в стилі ajax? Було б добре не блокувати сторінку.
Девід Чой,

Так, Сторінка не буде заблокована. Коли ви передасте URL-адресу як компонент для цього компонента, файл буде завантажений автоматично. Вам не потрібно буде нічого робити.
Хардік Модха,

Ще одне питання. У моєму випадку завантажуваний файл динамічно створюється з передачею деяких параметрів. Тож він насправді не має постійного розташування. Яку URL-адресу я надсилаю для цього типу сценаріїв? Наприклад, якщо я викликав axios.post ('api / getmyexcelfile', params);
Девід Чой,

Як зазначено у цій відповіді. В об'єкті відповіді axios всередині запиту є поле з назвою As responseURL, можливо, це URL-адреса, яку ви хочете.
Хардік Модха,

1
Я пішов за цим і зміг завантажити файл. Але файл зламаний (не працює). Однак, якщо я використовую переспрямування (window.location.href), файл завантажується і працює ідеально. Хтось може мені допомогти в цьому, будь ласка? ( Stackoverflow.com/questions/56306008 / ... )
Thidasa Панкадж

126

Більш загальне рішення

axios({
  url: 'http://api.dev/file-download', //your url
  method: 'GET',
  responseType: 'blob', // important
}).then((response) => {
   const url = window.URL.createObjectURL(new Blob([response.data]));
   const link = document.createElement('a');
   link.href = url;
   link.setAttribute('download', 'file.pdf'); //or any other extension
   document.body.appendChild(link);
   link.click();
});

Перевірте примхи на https://gist.github.com/javilobo8/097c30a233786be52070986d8cdb1743

Повні кредити на: https://gist.github.com/javilobo8


12
Дякую за рішення. Лише кілька приміток для інших: хоча це може працювати для багатьох випадків використання, але для великих розмірів файлів ви не зможете побачити хід завантаження. І це займе додаткову пам’ять у браузері. Як зазначено в інших рішеннях, але не описано, загальний підхід полягає у використанні заголовка "Content-Disposition: attachment;" тому браузер буде розглядати це як власне завантаження (вищезгаданий хід завантаження + пряме завантаження на диск).
John Lee

На стороні сервера, навіть коли я встановлюю заголовок Content-Desposition, здається, це не дозволяє прогресувати завантаження.
huggie

4
Дякую за це. Цікавився, чому вміст файлу відображався неправильно. Виявляється, я пропав безвістиresponseType: 'blob'
AliAvci

чи не завантажує це файл як відповідь спочатку на пам'ять (без того, щоб браузер фактично показував хід завантаження) лише тоді, коли файл завантажується як велика кількість в пам'ять, тоді лише браузер намагатиметься зберегти його у файлі для завантаження ..
Рікі -U

@ Ricky-U Так, ви маєте рацію, запит xhr буде надісланий, і коли відповідь надійде, він буде буферизований в пам'яті, а згодом, збережений у змінній responseпісля завершення. Потім createObjectURLстворює локальну URL-адресу для цих даних, до якої <a> може перейти.
Viney

50

Завантаження файлів (за допомогою Axios та Security)

Це насправді ще складніше, коли ви хочете завантажити файли за допомогою Axios та деяких засобів безпеки. Щоб хтось інший не витрачав занадто багато часу на це, дозвольте провести вас через це.

Вам потрібно зробити 3 речі:

1. Configure your server to permit the browser to see required HTTP headers
2. Implement the server-side service, and making it advertise the correct file type for the downloaded file.
3. Implementing an Axios handler to trigger a FileDownload dialog within the browser

Ці кроки здебільшого здійсненні, але вони значно ускладнюються відношенням браузера до CORS. Один крок за один раз:

1. Налаштуйте свій (HTTP) сервер

Застосовуючи транспортну безпеку, JavaScript, що виконується в браузері, може [за задумом] отримати доступ лише до 6 заголовків HTTP, які фактично надіслані сервером HTTP. Якщо ми хотіли б, щоб сервер запропонував ім'я файлу для завантаження, ми повинні повідомити браузер, що для «JavaScript» буде дозволено отримати доступ до інших заголовків, куди буде перенесено запропоноване ім’я файлу.

Припустимо - для обговорення - що ми хочемо, щоб сервер передавав запропоноване ім’я файлу в заголовку HTTP під назвою X-Suggested-Filename . Сервер HTTP повідомляє браузеру, що нормально виставляти цей отриманий користувацький заголовок JavaScript / Axios із таким заголовком:

Access-Control-Expose-Headers: X-Suggested-Filename

Точний спосіб налаштування сервера HTTP для встановлення цього заголовка залежить від продукту.

Подивитися Повне пояснення та детальний опис цих стандартних заголовків https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers .

2. Впровадити серверну службу

Тепер ваша реалізація серверної служби повинна виконувати 2 речі:

1. Create the (binary) document and assign correct ContentType to the response
2. Assign the custom header (X-Suggested-Filename) containing the suggested file name for the client

Це робиться різними способами залежно від обраного вами стеку технологій. Я накину приклад із використанням стандарту JavaEE 7, який повинен видавати звіт Excel:

@GET
@Path("/report/excel")
@Produces("application/vnd.ms-excel")
public Response getAllergyAndPreferencesReport() {

    // Create the document which should be downloaded
    final byte[] theDocumentData = .... 

    // Define a suggested filename
    final String filename = ... 

    // Create the JAXRS response
    // Don't forget to include the filename in 2 HTTP headers: 
    //
    // a) The standard 'Content-Disposition' one, and
    // b) The custom 'X-Suggested-Filename'  
    //
    final Response.ResponseBuilder builder = Response.ok(
            theDocumentData, "application/vnd.ms-excel")
            .header("X-Suggested-Filename", fileName);
    builder.header("Content-Disposition", "attachment; filename=" + fileName);

    // All Done.
    return builder.build();
}

Тепер служба випускає двійковий документ (у цьому випадку звіт Excel), встановлює правильний тип вмісту, а також надсилає власний заголовок HTTP, що містить запропоновану назву файлу, щоб використовувати під час збереження документа.

3. Впровадити обробник Axios для отриманого документа

Тут є кілька підводних каменів, тому давайте переконаємось, що всі деталі правильно налаштовані:

  1. Послуга реагує на @GET (тобто HTTP GET), тому виклик axios повинен бути 'axios.get (...)'.
  2. Документ передається як потік байтів, тому ви повинні сказати axios, щоб ставився до відповіді як до BLOB-масиву HTML5. (Тобто тип відповіді: "краплина" ).
  3. У цьому випадку для відкриття діалогового вікна браузера використовується бібліотека JavaScript для збереження файлів. Однак ви могли б вибрати інший.

Тоді скелет реалізації Axios мав би щось на зразок:

 // Fetch the dynamically generated excel document from the server.
 axios.get(resource, {responseType: 'blob'}).then((response) => {

    // Log somewhat to show that the browser actually exposes the custom HTTP header
    const fileNameHeader = "x-suggested-filename";
    const suggestedFileName = response.headers[fileNameHeader];'
    const effectiveFileName = (suggestedFileName === undefined
                ? "allergierOchPreferenser.xls"
                : suggestedFileName);
    console.log("Received header [" + fileNameHeader + "]: " + suggestedFileName
                + ", effective fileName: " + effectiveFileName);

    // Let the user save the file.
    FileSaver.saveAs(response.data, effectiveFileName);

    }).catch((response) => {
        console.error("Could not Download the Excel report from the backend.", response);
    });

21
Що таке "FileSaver"?
Main Pal

6
Це бібліотека для обробки файлів для завантаження, github.com/eligrey/FileSaver.js/#filesaverjs
Раді,

3
Це працює, але рекомендується використовувати content-dispositionзаголовок замість x-suggested-filename.
Росді Касім

14

Рішення Axios.post з IE та іншими браузерами

Я знайшов тут неймовірні рішення. Але вони часто не беруть до уваги проблеми з браузером IE. Можливо, це заощадить трохи часу комусь іншому.

 axios.post("/yourUrl"
                , data,
                {responseType: 'blob'}
            ).then(function (response) {
                    let fileName = response.headers["content-disposition"].split("filename=")[1];
                    if (window.navigator && window.navigator.msSaveOrOpenBlob) { // IE variant
                        window.navigator.msSaveOrOpenBlob(new Blob([response.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}),
                            fileName);
                    } else {
                        const url = window.URL.createObjectURL(new Blob([response.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}));
                        const link = document.createElement('a');
                        link.href = url;
                        link.setAttribute('download', response.headers["content-disposition"].split("filename=")[1]);
                        document.body.appendChild(link);
                        link.click();
                    }
                }
            );

наведений вище приклад для файлів Excel, але з невеликими змінами можна застосувати до будь-якого формату.

І на сервері я зробив це, щоб надіслати файл Excel.

response.contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"

response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=exceptions.xlsx")

9

Функція виклику API за допомогою axios:

  function getFileToDownload (apiUrl) {
     return axios.get(apiUrl, {
       responseType: 'arraybuffer',
       headers: {
         'Content-Type': 'application/json'
       }
     })
  }

Викличте функцію, а потім завантажте отриманий файл Excel:

getFileToDownload('putApiUrlHere')
  .then (response => {
      const type = response.headers['content-type']
      const blob = new Blob([response.data], { type: type, encoding: 'UTF-8' })
      const link = document.createElement('a')
      link.href = window.URL.createObjectURL(blob)
      link.download = 'file.xlsx'
      link.click()
  })

8
        axios.get(
            '/app/export'
        ).then(response => {    
            const url = window.URL.createObjectURL(new Blob([response]));
            const link = document.createElement('a');
            link.href = url;
            const fileName = `${+ new Date()}.csv`// whatever your file name .
            link.setAttribute('download', fileName);
            document.body.appendChild(link);
            link.click();
            link.remove();// you need to remove that elelment which is created before.
})

8

Це дуже простий код javascript для запуску завантаження для користувача:

window.open("<insert URL here>")

Вам не потрібні / потрібні осьові для цієї операції; це повинно бути стандартним, щоб просто дозволити браузеру робити це.

Примітка. Якщо вам потрібна авторизація для завантаження, це може не спрацювати. Я майже впевнений, що ви можете використовувати файли cookie для авторизації такого запиту за умови, що він знаходиться в одному домені, але незалежно від цього, це може не спрацювати відразу в такому випадку.


Щодо того, чи можливо це ... не за допомогою вбудованого механізму завантаження файлів, ні .


12
Заголовки авторизації?
Еяз Карім

Що робити, якщо вам потрібно надіслати маркер?
user3808307

Якщо ви керуєте сервером, ви можете просто зберегти маркер доступу як файл cookie, і браузер додасть його до будь-якого запиту на ваш сервер. medium.com/@ryanchenkie_40935/…
Multihunter

1
@CharithJayasanka Так, я так вважаю.
Multihunter

2

Фокус полягає в тому, щоб зробити невидимий прив'язний тег в render()і додати React, refщо дозволяє викликати клацання, коли ми отримаємо відповідь axios:

class Example extends Component {
    state = {
        ref: React.createRef()
    }

    exportCSV = () => {
        axios.get(
            '/app/export'
        ).then(response => {
            let blob = new Blob([response.data], {type: 'application/octet-stream'})
            let ref = this.state.ref
            ref.current.href = URL.createObjectURL(blob)
            ref.current.download = 'data.csv'
            ref.current.click()
        })
    }

    render(){
        return(
            <div>
                <a style={{display: 'none'}} href='empty' ref={this.state.ref}>ref</a>
                <button onClick={this.exportCSV}>Export CSV</button>
            </div>
        )
    }
}

Ось документація: https://reactjs.org/docs/refs-and-the-dom.html . Ви можете знайти подібну ідею тут: https://thewebtier.com/snippets/download-files-with-axios/ .


0

Це спрацювало для мене. я впровадив це рішення в responseJS

const requestOptions = {`enter code here`
method: 'GET',
headers: { 'Content-Type': 'application/json' }
};

fetch(`${url}`, requestOptions)
.then((res) => {
    return res.blob();
})
.then((blob) => {
    const href = window.URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = href;
    link.setAttribute('download', 'config.json'); //or any other extension
    document.body.appendChild(link);
    link.click();
})
.catch((err) => {
    return Promise.reject({ Error: 'Something Went Wrong', err });
})

-1

Для запиту axios POST запит має бути приблизно таким: Ключ тут полягає в тому, що поля responseTypeand і headerповинні знаходитися в 3-му параметрі Post. 2-й параметр - це параметри програми.

export const requestDownloadReport = (requestParams) => async dispatch => { 
  let response = null;
  try {
    response = await frontEndApi.post('createPdf', {
      requestParams: requestParams,
    },
    {
      responseType: 'arraybuffer', // important...because we need to convert it to a blob. If we don't specify this, response.data will be the raw data. It cannot be converted to blob directly.
      headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/pdf'
      }
  });          
  }
  catch(err) {
    console.log('[requestDownloadReport][ERROR]', err);
    return err
  }

  return response;
}

-4

Моя відповідь - цілковитий злом - я щойно створив посилання, схоже на кнопку, і додав до нього URL-адресу.

<a class="el-button"
  style="color: white; background-color: #58B7FF;"
  :href="<YOUR URL ENDPOINT HERE>"
  :download="<FILE NAME NERE>">
<i class="fa fa-file-excel-o"></i>&nbsp;Excel
</a>

Я використовую чудові VueJs, отже, непарні анотації , однак це рішення є агностичним для фреймворку. Ідея підійде для будь-якого дизайну на основі HTML.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.