Chcę wysłać „żądanie pobrania AJAX” po kliknięciu przycisku, więc spróbowałem w ten sposób:
javascript:
var xhr = new XMLHttpRequest();
xhr.open("GET", "download.php");
xhr.send();
download.php:
<?
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename= file.txt");
header("Content-Transfer-Encoding: binary");
readfile("file.txt");
?>
ale nie działa zgodnie z oczekiwaniami, jak mogę to zrobić? Z góry dziękuję
location.href='download.php';
Odpowiedzi:
Aktualizacja 27 kwietnia 2015 r
Przejście do sceny HTML5 to atrybut pobierania . Jest obsługiwany w przeglądarkach Firefox i Chrome, a wkrótce pojawi się w IE11. W zależności od potrzeb możesz go użyć zamiast żądania AJAX (lub użyć
window.location
), o ile plik, który chcesz pobrać, ma to samo źródło co Twoja witryna.Zawsze możesz wykonać żądanie /
window.location
rezerwę AJAX, używając JavaScript do sprawdzenia, czydownload
jest obsługiwana, a jeśli nie, przełączając ją na wywołaniewindow.location
.Oryginalna odpowiedź
Żądanie AJAX nie może otworzyć monitu pobierania, ponieważ fizycznie musisz przejść do pliku, aby wyświetlić monit o pobranie. Zamiast tego możesz użyć funkcji sukcesu, aby przejść do download.php. Spowoduje to otwarcie monitu o pobranie, ale nie zmieni bieżącej strony.
$.ajax({ url: 'download.php', type: 'POST', success: function() { window.location = 'download.php'; } });
Mimo że to odpowiada na pytanie, lepiej po prostu użyć
window.location
i całkowicie uniknąć żądania AJAX.źródło
Aby przeglądarka pobierała plik, musisz wykonać takie żądanie:
function downloadFile(urlToSend) { var req = new XMLHttpRequest(); req.open("GET", urlToSend, true); req.responseType = "blob"; req.onload = function (event) { var blob = req.response; var fileName = req.getResponseHeader("fileName") //if you have the fileName header available var link=document.createElement('a'); link.href=window.URL.createObjectURL(blob); link.download=fileName; link.click(); }; req.send(); }
źródło
<a>
tag za pomocą JS, również „w locie”, ale musisz go dołączyć dodocument.body
. Na pewno chcesz to ukryć w tym samym czasie.W rzeczywistości wcale nie potrzebujesz do tego Ajaxa. Jeśli po prostu ustawisz „download.php” jako href na przycisku lub, jeśli nie jest to link, użyj:
window.location = 'download.php';
Przeglądarka powinna rozpoznać pobieranie binarne i nie ładować rzeczywistej strony, ale po prostu udostępniać plik jako plik do pobrania.
źródło
window.location
to JavaScript.Rozwiązanie dla różnych przeglądarek, przetestowane na Chrome, Firefox, Edge, IE11.
W DOM dodaj ukryty tag linku:
<a id="target" style="display: none"></a>
Następnie:
var req = new XMLHttpRequest(); req.open("GET", downloadUrl, true); req.responseType = "blob"; req.setRequestHeader('my-custom-header', 'custom-value'); // adding some headers (if needed) req.onload = function (event) { var blob = req.response; var fileName = null; var contentType = req.getResponseHeader("content-type"); // IE/EDGE seems not returning some response header if (req.getResponseHeader("content-disposition")) { var contentDisposition = req.getResponseHeader("content-disposition"); fileName = contentDisposition.substring(contentDisposition.indexOf("=")+1); } else { fileName = "unnamed." + contentType.substring(contentType.indexOf("/")+1); } if (window.navigator.msSaveOrOpenBlob) { // Internet Explorer window.navigator.msSaveOrOpenBlob(new Blob([blob], {type: contentType}), fileName); } else { var el = document.getElementById("target"); el.href = window.URL.createObjectURL(blob); el.download = fileName; el.click(); } }; req.send();
źródło
Authorization
?window.URL.revokeObjectURL(el.href);
późniejel.click()
?To jest możliwe. Pobieranie można rozpocząć z poziomu funkcji Ajax, na przykład zaraz po utworzeniu pliku .csv.
Mam funkcję Ajax, która eksportuje bazę danych kontaktów do pliku .csv, a zaraz po jego zakończeniu automatycznie rozpoczyna pobieranie pliku .csv. Tak więc po otrzymaniu odpowiedzi i wszystko jest w porządku, przekierowuję przeglądarkę w ten sposób:
window.location="download.php?filename=export.csv";
Mój plik download.php wygląda następująco:
<?php $file = $_GET['filename']; header("Cache-Control: public"); header("Content-Description: File Transfer"); header("Content-Disposition: attachment; filename=".$file.""); header("Content-Transfer-Encoding: binary"); header("Content-Type: binary/octet-stream"); readfile($file); ?>
Nie ma żadnego odświeżania strony, a pobieranie pliku rozpoczyna się automatycznie.
UWAGA - Przetestowano w następujących przeglądarkach:
Chrome v37.0.2062.120 Firefox v32.0.1 Opera v12.17 Internet Explorer v11
źródło
wolę
location.assign(url);
Pełny przykład składni:
document.location.assign('https://www.urltodocument.com/document.pdf');
developer.mozilla.org/en-US/docs/Web/API/Location. assign
źródło
Dekodowanie nazwy pliku z nagłówka jest nieco bardziej złożone ...
var filename = "default.pdf"; var disposition = req.getResponseHeader('Content-Disposition'); if (disposition && disposition.indexOf('attachment') !== -1) { var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/; var matches = filenameRegex.exec(disposition); if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, ''); }
źródło
To rozwiązanie nie różni się zbytnio od powyższych, ale jak dla mnie działa bardzo dobrze i uważam, że jest czyste.
Proponuję zakodować base64 po stronie serwera plików (base64_encode (), jeśli używasz PHP) i wysłać zakodowane dane base64 do klienta
Na kliencie robisz to:
let blob = this.dataURItoBlob(THE_MIME_TYPE + "," + response.file); let uri = URL.createObjectURL(blob); let link = document.createElement("a"); link.download = THE_FILE_NAME, link.href = uri; document.body.appendChild(link); link.click(); document.body.removeChild(link);
Ten kod umieszcza zakodowane dane w odsyłaczu i symuluje kliknięcie odsyłacza, a następnie usuwa je.
źródło
Twoje potrzeby są zaspokojone przez
window.location('download.php');
Ale myślę, że musisz przekazać plik do pobrania, a nie zawsze pobrać ten sam plik i dlatego używasz żądania, jedną z opcji jest utworzenie pliku php tak prostego jak showfile.php i wykonaj prośbę, taką jak
var myfile = filetodownload.txt var url = "shofile.php?file=" + myfile ; ajaxRequest.open("GET", url, true);
showfile.php
<?php $file = $_GET["file"] echo $file;
gdzie plik jest nazwą pliku przekazaną w żądaniu za pośrednictwem funkcji Get lub Post, a następnie po prostu przechwyć odpowiedź w funkcji
if(ajaxRequest.readyState == 4){ var file = ajaxRequest.responseText; window.location = 'downfile.php?file=' + file; } }
źródło
istnieje inne rozwiązanie umożliwiające pobranie strony internetowej w Ajax. Ale mam na myśli stronę, którą należy najpierw przetworzyć, a następnie pobrać.
Najpierw musisz oddzielić przetwarzanie strony od pobierania wyników.
1) W wywołaniu Ajax wykonywane są tylko obliczenia strony.
Mam nadzieję, że to rozwiązanie może być przydatne dla wielu, tak jak dla mnie.
źródło
Dla tych, którzy szukają bardziej nowoczesnego podejścia, możesz użyć
fetch API
. Poniższy przykład pokazuje, jak pobrać plik arkusza kalkulacyjnego. Można to łatwo zrobić za pomocą następującego kodu.fetch(url, { body: JSON.stringify(data), method: 'POST', headers: { 'Content-Type': 'application/json; charset=utf-8' }, }) .then(response => response.blob()) .then(response => { const blob = new Blob([response], {type: 'application/application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}); const downloadUrl = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = downloadUrl; a.download = "file.xlsx"; document.body.appendChild(a); a.click(); })
Uważam, że to podejście jest dużo łatwiejsze do zrozumienia niż inne
XMLHttpRequest
rozwiązania. Ma również podobną składnię dojQuery
podejścia, bez konieczności dodawania jakichkolwiek dodatkowych bibliotek.Oczywiście radziłbym sprawdzić, którą przeglądarkę tworzysz, ponieważ to nowe podejście nie będzie działać w IE. Pełną listę zgodności przeglądarek można znaleźć pod poniższym linkiem .
Ważne : W tym przykładzie wysyłam żądanie JSON do serwera nasłuchującego na podanym
url
. Tourl
musi być ustawione, na moim przykładzie zakładam, że znasz tę część. Weź również pod uwagę nagłówki potrzebne do działania żądania. Ponieważ wysyłam JSON, muszę dodaćContent-Type
nagłówek i ustawić go naapplication/json; charset=utf-8
, aby poinformować serwer o typie żądania, które otrzyma.źródło
Rozwiązanie @Joao Marcos działa u mnie, ale musiałem zmodyfikować kod, aby działał w IE, poniżej czy jak wygląda kod
downloadFile(url,filename) { var that = this; const extension = url.split('/').pop().split('?')[0].split('.').pop(); var req = new XMLHttpRequest(); req.open("GET", url, true); req.responseType = "blob"; req.onload = function (event) { const fileName = `${filename}.${extension}`; const blob = req.response; if (window.navigator.msSaveBlob) { // IE window.navigator.msSaveOrOpenBlob(blob, fileName); } const link = document.createElement('a'); link.href = window.URL.createObjectURL(blob); link.download = fileName; link.click(); URL.revokeObjectURL(link.href); }; req.send(); },
źródło