Axios kullanarak dosyalar nasıl indirilir


113

GET ve POST gibi temel http istekleri için aksiyolar kullanıyorum ve iyi çalışıyor. Artık Excel dosyalarını da indirebilmem gerekiyor. Bu aksiyolar ile mümkün mü? Varsa, herhangi birinin örnek kodu var mı? Değilse, aynısını yapmak için bir React uygulamasında başka ne kullanabilirim?


Excel dosyasını indirmek için bu çözümü kullanabiliriz. stackoverflow.com/questions/57127361/…
Md. Nazrul Islam

Yanıtlar:


100

Yanıt indirilebilir bir dosyayla geldiğinde, yanıt başlıkları aşağıdaki gibi olacaktır:

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

Yapabileceğiniz şey, gizli bir iframe içerecek ayrı bir bileşen oluşturmaktır.

  import * as React from 'react';

  var MyIframe = React.createClass({

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

Şimdi, indirilebilir dosyanın url'sini bu bileşene pervane olarak iletebilirsiniz, Yani bu bileşen prop alacağı zaman, yeniden işlenecek ve dosya indirilecektir.

Düzenleme: js-dosya indirme modülünü de kullanabilirsiniz . Github deposuna bağlantı

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

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

Bu yardımcı olur umarım :)


1
Teşekkür ederim. Bunun ajax tarzında olup olmadığını bana söyleyebilir misin? Sayfayı engellememek iyi olur.
David Choi

Evet, Sayfa engellenmeyecek. URL'yi bu bileşene uygun olarak ilettiğinizde, dosya otomatik olarak indirilecektir. Hiçbir şey yapmanıza gerek kalmayacak.
Hardik Modha

Bir soru daha. Benim durumumda indirilmekte olan dosya, bazı parametreler geçirilerek dinamik olarak oluşturulur. Yani gerçekten tutarlı bir konuma sahip değil. Bu tür bir senaryo için gönderdiğim url nedir? Örneğin axios.post ('api / getmyexcelfile', params) çağırırsam;
David Choi

Bu cevapta belirtildiği gibi . Axios yanıt nesnesinde, istek içinde As adlı bir alan vardır responseURL, belki de istediğiniz URL budur.
Hardik Modha

1
Bunu takip ettim ve dosyayı indirebildim. Ancak dosya bozuk (çalışmıyor). Ancak, yeniden yönlendirme kullanırsam (window.location.href) dosya indirilir ve mükemmel çalışır. Biri bana bu konuda yardım edebilir mi lütfen? ( stackoverflow.com/questions/56306008/… )
Thidasa Pankaja

118

Daha genel bir çözüm

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 adresindeki tuhaflıkları kontrol edin

Tam krediler: https://gist.github.com/javilobo8


11
Çözüm için teşekkürler. Başkaları için sadece birkaç not: Bu birçok kullanım durumunda işe yarayabilir, ancak büyük dosya boyutları için indirme ilerlemesini göremezsiniz. Ve tarayıcıda fazladan hafıza alacaktır. Diğer çözümlerde de belirtildiği gibi, ancak açıklanmadığı gibi, genel yaklaşım 'Content-Disposition: attachment;' başlığını kullanmaktır. bu nedenle tarayıcı bunu yerel bir indirme olarak ele alacaktır (yukarıda bahsedilen indirme ilerlemesi + diske doğrudan indirme).
John Lee

Sunucu tarafında Content-Desposition başlığını belirlediğimde bile indirme işleminin ilerlemesine izin vermiyor gibi görünüyor.
huggie

4
Bunun için teşekkürler. Dosya içeriğinin neden doğru görünmediğini merak ediyordum. Kaybolduğum ortaya çıktıresponseType: 'blob'
AliAvci

bu, dosyayı önce belleğe bir yanıt olarak indirmez (tarayıcı aslında indirme ilerlemesini göstermeden) yalnızca dosya bellekte bir blob olarak indirildiğinde, yalnızca tarayıcı onu indirme dosyasına kaydetmeye çalışır ..
Ricky -U

@ Ricky-U Evet haklısınız, xhr isteği gönderilecek ve yanıt geldiğinde bellekte arabelleğe alınacak ve daha responsesonra tamamlandığında değişken olarak saklanacaktır . Ardından createObjectURLbu verilere bir <a> 'nin gidebileceği yerel bir url oluşturur.
Viney

48

Dosyaları İndirme (Axios ve Güvenlik kullanarak)

Axios ve bazı güvenlik araçlarını kullanarak dosya indirmek istediğinizde bu aslında daha da karmaşıktır. Başkalarının bunu çözmek için çok fazla zaman harcamasını önlemek için, size bu konuda yol göstermeme izin verin.

3 şey yapmanız gerekiyor:

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

Bu adımlar çoğunlukla uygulanabilir - ancak tarayıcının CORS ile ilişkisi nedeniyle önemli ölçüde karmaşıktır. Adım adım:

1. (HTTP) sunucunuzu yapılandırın

Taşıma güvenliği kullanılırken, bir tarayıcı içinde çalıştırılan JavaScript [tasarım gereği], gerçekte HTTP sunucusu tarafından gönderilen HTTP başlıklarının yalnızca 6'sına erişebilir. Sunucunun indirme için bir dosya adı önermesini istiyorsak, JavaScript'in önerilen dosya adının taşınacağı diğer başlıklara erişim vermesi için tarayıcıya "Tamam" olduğunu bildirmeliyiz.

Tartışma adına, sunucunun önerilen dosya adını X-Suggested-Filename adlı bir HTTP üstbilgisi içinde iletmesini istediğimizi varsayalım . HTTP sunucusu olduğu tarayıcıya bildirir Tamam aşağıdaki başlığıyla JavaScript / AXIOS bu alınan özel üstbilgi açığa çıkarmak için:

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

HTTP sunucunuzu bu başlığı ayarlayacak şekilde yapılandırmanın tam yolu üründen ürüne değişir.

Bu standart başlıkların tam açıklaması ve ayrıntılı açıklaması için https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers adresine bakın .

2. Sunucu tarafı hizmeti uygulayın

Sunucu tarafı hizmet uygulamanız şimdi 2 şey gerçekleştirmelidir:

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

Bu, seçtiğiniz teknoloji yığınına bağlı olarak farklı şekillerde yapılır. Bir Excel raporu vermesi gereken JavaEE 7 standardını kullanarak bir örnek çizeceğim:

@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();
}

Hizmet artık ikili belgeyi (bu durumda bir Excel raporu) yayar, doğru içerik türünü ayarlar ve ayrıca belgeyi kaydederken kullanmak üzere önerilen dosya adını içeren özel bir HTTP üstbilgisi gönderir.

3. Alınan belge için bir Axios işleyicisi uygulayın

Burada birkaç tuzak var, bu nedenle tüm ayrıntıların doğru şekilde yapılandırıldığından emin olalım:

  1. Hizmet @GET'e (yani HTTP GET) yanıt verir, bu nedenle axios çağrısı 'axios.get (...)' olmalıdır.
  2. Belge bir bayt akışı olarak iletilir, bu nedenle axios'a yanıtı bir HTML5 Blobu olarak değerlendirmesini söylemelisiniz. (Yani responseType: 'blob' ).
  3. Bu durumda, dosya koruyucu JavaScript kitaplığı tarayıcı iletişim kutusunu açmak için kullanılır. Ancak başka bir tane seçebilirsin.

İskelet Axios uygulaması şu satırlarda bir şey olacaktır:

 // 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);
    });

20
"FileSaver" nedir?
Main Pal

6
İndirme dosyalarını işlemek için bir kitaplık, github.com/eligrey/FileSaver.js/#filesaverjs
Radi

2
Bu çalışır, ancak bunun content-dispositionyerine başlık kullanılması önerilir x-suggested-filename.
Rosdi Kasim

13

IE ve diğer tarayıcılarla Axios.post çözümü

Burada bazı inanılmaz çözümler buldum. Ancak IE tarayıcı ile ilgili sorunları sıklıkla dikkate almazlar. Belki başkasına biraz zaman kazandırır.

 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();
                    }
                }
            );

Yukarıdaki örnek excel dosyaları içindir, ancak küçük değişikliklerle herhangi bir formata uygulanabilir.

Ve sunucuda bunu bir excel dosyası göndermek için yaptım.

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

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

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

Axios ile API çağrısı yapma işlevi:

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

İşlevi çağırın ve ardından aldığınız excel dosyasını indirin:

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()
  })

6

Kullanıcı için bir indirme işlemini tetiklemek için çok basit bir javascript kodu:

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

Bu işlem için aksiyo istemiyorsunuz / ihtiyacınız yok; sadece tarayıcının bir şeyi yapmasına izin vermek standart olmalıdır.

Not: İndirme için yetkilendirmeye ihtiyacınız varsa, bu işe yaramayabilir. Aynı etki alanında olması koşuluyla, bunun gibi bir isteği yetkilendirmek için çerezleri kullanabileceğinizden oldukça eminim, ancak ne olursa olsun, böyle bir durumda bu hemen işe yaramayabilir.


Bu ister gelince mümkün ... değil dahili dosya indirme mekanizması ile, hayır .


12
Yetkilendirme başlıkları?
Ejaz Karim

Ya bir belirteç göndermeniz gerekirse?
user3808307

Sunucuyu kontrol ediyorsanız, erişim jetonunu bir çerez olarak saklayabilirsiniz ve tarayıcı bunu sunucunuzdaki herhangi bir isteğe ekleyecektir. medium.com/@ryanchenkie_40935/…
Multihunter

Bu sadece bir GET ise kullanılabilir değil mi?
Charith Jayasanka

1
@CharithJayasanka Evet, öyle olduğuna inanıyorum.
Multihunter

2

İşin püf noktası, içinde görünmez bir bağlantı etiketi yapmak ve axios yanıtına sahip olduğumuzda bir tıklamayı tetiklemeye izin veren render()bir React refeklemektir:

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>
        )
    }
}

Belgeler şu şekildedir: https://reactjs.org/docs/refs-and-the-dom.html . Burada benzer bir fikir bulabilirsiniz: https://thewebtier.com/snippets/download-files-with-axios/ .


-1

Axios POST isteği için istek şu şekilde olmalıdır: Buradaki anahtar, responseTypeve headeralanlarının Post'un 3. parametresinde olması gerektiğidir. 2. parametre uygulama parametreleridir.

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

Cevabım tam bir hack - az önce düğme gibi görünen bir bağlantı oluşturdum ve buna URL'yi ekledim.

<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>

Mükemmel VueJ'leri kullanıyorum, bu nedenle garip anotasyonlar , ancak bu çözüm çerçeveden bağımsızdır. Fikir, herhangi bir HTML tabanlı tasarım için işe yarayacaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.