Mam aplikację javascript, która wysyła żądania ajax POST do określonego adresu URL. Odpowiedź może być łańcuchem JSON lub plikiem (jako załącznik). Mogę łatwo wykryć typ zawartości i dyspozycję zawartości w moim wywołaniu ajax, ale kiedy wykryję, że odpowiedź zawiera plik, jak mogę zaoferować klientowi pobranie go? Przeczytałem tutaj wiele podobnych wątków, ale żaden z nich nie zawiera odpowiedzi, której szukam.
Proszę, proszę, nie publikuj odpowiedzi sugerujących, że nie powinienem używać do tego ajax, lub że powinienem przekierować przeglądarkę, ponieważ żadna z tych opcji nie jest możliwa. Użycie zwykłego formularza HTML również nie jest opcją. Muszę pokazać klientowi okno dialogowe pobierania. Czy można to zrobić i jak?
javascript
jquery
ajax
Pavle Predic
źródło
źródło
Odpowiedzi:
Utwórz formularz, użyj metody POST, prześlij formularz - nie ma potrzeby używania elementu iframe. Kiedy strona serwera odpowie na żądanie, napisz nagłówek odpowiedzi dla typu MIME pliku, a wyświetli się okno dialogowe pobierania - robiłem to wiele razy.
Chcesz mieć rodzaj aplikacji / pobierania - po prostu wyszukaj, jak zapewnić pobieranie dla dowolnego używanego języka.
źródło
Nie poddawaj się tak szybko, ponieważ można to zrobić (w nowoczesnych przeglądarkach) za pomocą części FileAPI:
Oto stara wersja korzystająca z jQuery.ajax. Może przekształcać dane binarne, gdy odpowiedź zostanie przekonwertowana na ciąg jakiegoś zestawu znaków.
źródło
document.body.removeChild(a);
var blob =this.responce; /** if (typeof File === 'function') { try { blob = new File([this.response], filename, { type: type }); } catch (e) { /* Edge */ } } if (typeof blob === 'undefined') { blob = new Blob([this.response], { type: type }); } */
window.location.href = downloadUrl
zamiastwindow.location = downloadUrl
Napotkałem ten sam problem i udało mi się go rozwiązać. Oto mój przypadek użycia.
„ Opublikuj dane JSON na serwerze i otrzymaj plik programu Excel. Ten plik programu Excel jest tworzony przez serwer i zwracany w odpowiedzi na klienta. Pobierz tę odpowiedź jako plik o niestandardowej nazwie w przeglądarce ”
Powyższy fragment kodu wykonuje tylko następujące czynności
Tutaj musimy ostrożnie ustawić kilka rzeczy po stronie serwera. Ustawiłem kilka nagłówków w Python Django HttpResponse. Musisz odpowiednio je ustawić, jeśli używasz innych języków programowania.
Ponieważ tutaj pobieram xls (excel), dostosowałem contentType do ponad jednego. Musisz ustawić go zgodnie z typem pliku. Możesz użyć tej techniki do pobierania dowolnego rodzaju plików.
źródło
Jakiego języka używasz po stronie serwera? W mojej aplikacji mogę łatwo pobrać plik z wywołania AJAX, ustawiając odpowiednie nagłówki w odpowiedzi PHP:
Ustawianie nagłówków po stronie serwera
To faktycznie przekieruje przeglądarkę na tę stronę pobierania, ale jak już powiedział @ahren w swoim komentarzu, nie będzie nawigować poza bieżącą stronę.
Chodzi o ustawienie prawidłowych nagłówków, więc jestem pewien, że znajdziesz odpowiednie rozwiązanie dla używanego języka po stronie serwera, jeśli nie jest to PHP.
Obsługa odpowiedzi po stronie klienta
Zakładając, że już wiesz, jak wykonać wywołanie AJAX, po stronie klienta wykonasz żądanie AJAX do serwera. Serwer następnie generuje link, z którego można pobrać ten plik, np. „Adres URL przesyłania dalej”, na który chcesz wskazać. Na przykład serwer odpowiada:
Podczas przetwarzania odpowiedzi wstrzykujesz do
iframe
swojego ciała i ustawiasziframe
SRC na adres URL, który właśnie otrzymałeś w ten sposób (używając jQuery dla ułatwienia tego przykładu):Jeśli ustawiłeś prawidłowe nagłówki, jak pokazano powyżej, iframe wymusi okno pobierania bez odsuwania przeglądarki od bieżącej strony.
Uwaga
Dodatkowy dodatek w stosunku do twojego pytania; Myślę, że najlepiej jest zawsze zwracać JSON, gdy żąda się czegoś z technologią AJAX. Po otrzymaniu odpowiedzi JSON możesz zdecydować po stronie klienta, co z nią zrobić. Być może na przykład później chcesz, aby użytkownik kliknął łącze pobierania do adresu URL zamiast wymuszać bezpośrednie pobieranie, w bieżącej konfiguracji musisz zaktualizować zarówno po stronie klienta, jak i serwera.
źródło
Dla tych, którzy szukają rozwiązania z perspektywy Angular, zadziałało to dla mnie:
źródło
link.download = ""
powoduje utworzenie losowej nazwy pliku guid ilink.download = null
utworzenie pliku o nazwie „null”.INPUT
elementuHTMLInputElement.files
. Zobacz dokumentację MDN na wejściu pliku, aby uzyskać więcej szczegółów.Oto, jak mam to działa https://stackoverflow.com/a/27563953/2845977
Zaktualizowana odpowiedź za pomocą download.js
źródło
success: function (response, status, request) { download(response, "filename.txt", "application/text"); }
Widzę, że już znalazłeś rozwiązanie, ale chciałem tylko dodać informacje, które mogą pomóc komuś, kto próbuje osiągnąć to samo przy dużych żądaniach POST.
Miałem ten sam problem kilka tygodni temu, w rzeczywistości nie można uzyskać „czystego” pobrania przez AJAX, Grupa Filament utworzyła wtyczkę jQuery, która działa dokładnie tak, jak już się dowiedziałeś, nazywa się jQuery File Pobierz jednak ta technika ma wadę.
Jeśli wysyłasz duże żądania za pośrednictwem AJAX (powiedzmy, pliki + 1 MB), będzie to miało negatywny wpływ na czas reakcji. W wolnych połączeń internetowych musisz czekać wiele , dopóki żądanie jest wysyłane, a także czekać na pliku do pobrania. To nie jest jak natychmiastowe „kliknięcie” => „popup” => „rozpoczęcie pobierania”. To bardziej jak „kliknięcie” => „poczekaj, aż dane zostaną wysłane” => „poczekaj na odpowiedź” => „rozpocznij pobieranie”, co sprawia, że plik ma dwukrotnie większy rozmiar, ponieważ musisz poczekać na wysłanie żądania przez AJAX i odzyskaj jako plik do pobrania.
Jeśli pracujesz z małymi rozmiarami plików <1 MB, nie zauważysz tego. Ale jak odkryłem we własnej aplikacji, w przypadku większych plików jest to prawie nie do zniesienia.
Moja aplikacja pozwala użytkownikom eksportować obrazy generowane dynamicznie, obrazy te są wysyłane za pośrednictwem żądań POST w formacie base64 na serwer (jest to jedyny możliwy sposób), a następnie przetwarzane i wysyłane z powrotem do użytkowników w postaci plików .png, .jpg, base64 ciągi obrazów + 1 MB są ogromne, co zmusza użytkowników do czekania dłużej niż jest to konieczne do rozpoczęcia pobierania pliku. W wolnych połączeniach internetowych może to być naprawdę denerwujące.
Moim rozwiązaniem było tymczasowe zapisanie pliku na serwerze, gdy będzie on gotowy, dynamiczne generowanie linku do pliku w postaci przycisku, który zmienia się między stanami „Proszę czekać ...” i „Pobierz” i jednocześnie czas, wydrukuj obraz base64 w wyskakującym oknie podglądu, aby użytkownicy mogli kliknąć prawym przyciskiem myszy i zapisać go. To sprawia, że cały czas oczekiwania jest bardziej znośny dla użytkowników, a także przyspiesza.
Aktualizacja 30 września 2014:
Pobierz przykładowy skrypt:
Wiem, że jest to o wiele więcej niż to, o co poprosił PO, ale czułem, że dobrze byłoby zaktualizować moją odpowiedź o moje ustalenia. Kiedy szukałem rozwiązań mojego problemu, przeczytałem wiele wątków „Pobierz z danych AJAX POST”, które nie dały mi odpowiedzi, której szukałem, mam nadzieję, że te informacje pomogą komuś, kto chce osiągnąć coś takiego.
źródło
jQuery File Download
Tylko przekierować mnie do adresu URL. Ja nazywam to tak:jQuery.download("api/ide/download-this-file.php", {filePath: path2Down}, "POST");
.Chcę wskazać pewne trudności, które pojawiają się podczas korzystania z techniki w zaakceptowanej odpowiedzi, tj. Przy użyciu formularza:
Nie można ustawić nagłówków na żądanie. Jeśli schemat uwierzytelniania obejmuje nagłówki, token Json-Web przekazany w nagłówku autoryzacji, musisz znaleźć inny sposób wysłania go, na przykład jako parametr zapytania.
Naprawdę nie wiadomo, kiedy prośba się zakończyła. Cóż, możesz użyć pliku cookie, który jest ustawiany w odpowiedzi, jak zrobiono to przez jquery.fileDownload , ale DALEKO od ideału. Nie będzie działać w przypadku równoczesnych żądań i ulegnie awarii, jeśli odpowiedź nigdy nie nadejdzie.
Jeśli serwer zareaguje na błąd, użytkownik zostanie przekierowany na stronę błędu.
Możesz używać tylko typów treści obsługiwanych przez formularz . Co oznacza, że nie możesz używać JSON.
Skończyłem przy użyciu metody zapisywania pliku na S3 i wysyłania wstępnie podpisanego adresu URL, aby uzyskać plik.
źródło
Dla tych, którzy szukają bardziej nowoczesnego podejścia, możesz skorzystać z
fetch API
. Poniższy przykład pokazuje, jak pobrać plik arkusza kalkulacyjnego. Można to łatwo zrobić za pomocą następującego kodu.Uważam, że takie podejście jest znacznie łatwiejsze do zrozumienia niż inne
XMLHttpRequest
rozwiązania. Ponadto ma podobną składnię do tegojQuery
podejścia, bez potrzeby dodawania żadnych 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ę kompatybilności przeglądarki można znaleźć pod następującym [linkiem] [1].
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 żądania. Ponieważ wysyłam JSON, muszę dodaćContent-Type
nagłówek i ustawić go naapplication/json; charset=utf-8
, aby serwer wiedział, jaki typ żądania otrzyma.źródło
Oto moje rozwiązanie przy użyciu tymczasowego ukrytego formularza.
Zauważ, że masowo używam JQuery, ale możesz zrobić to samo z natywnym JS.
źródło
Jak stwierdzili inni, możesz utworzyć i przesłać formularz do pobrania za pomocą żądania POST. Jednak nie musisz tego robić ręcznie.
Jedną naprawdę prostą biblioteką do robienia tego dokładnie jest jquery.redirect . Zapewnia interfejs API podobny do standardowej
jQuery.post
metody:źródło
To pytanie sprzed 3 lat, ale dzisiaj miałem ten sam problem. Szukałem twojego edytowanego rozwiązania, ale myślę, że może poświęcić wydajność, ponieważ musi złożyć podwójne żądanie. Jeśli więc ktoś potrzebuje innego rozwiązania, które nie oznacza dwukrotnego wezwania serwisu, to właśnie tak to zrobiłem:
Ten formularz służy tylko do wywołania usługi i unikania korzystania z window.location (). Następnie wystarczy po prostu przesłać formularz z jquery, aby zadzwonić do serwisu i pobrać plik. Jest to dość proste, ale w ten sposób możesz pobrać za pomocą POST . Teraz myślę, że może to być łatwiejsze, jeśli usługa, do której dzwonisz, to GET , ale to nie moja sprawa.
źródło
Użyłem tego FileSaver.js . W moim przypadku z plikami csv zrobiłem to (w coffescript):
Myślę, że w najbardziej skomplikowanym przypadku dane muszą być przetwarzane poprawnie. Pod maską FileSaver.js zaimplementuj to samo podejście, co odpowiedź Jonathana Amend .
źródło
patrz: http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/ zwróci w odpowiedzi obiekt blob, który można następnie umieścić w przeglądarce plików
źródło
Aby uzyskać odpowiedź Jonathana Amendsa na pracę w Edge, wprowadziłem następujące zmiany:
do tego
Wolę zamieścić to jako komentarz, ale nie mam na to wystarczającej reputacji
źródło
Oto moje rozwiązanie, zebrane z różnych źródeł: Implementacja po stronie serwera:
Implementacja po stronie klienta (przy użyciu jquery):
źródło
istnieje inne rozwiązanie, aby pobrać stronę internetową w ajax. Mam jednak na myśli stronę, którą najpierw trzeba przetworzyć, a następnie pobrać.
Najpierw musisz oddzielić przetwarzanie strony od pobierania wyników.
1) Tylko wywołania strony są wykonywane w wywołaniu ajax.
Mam nadzieję, że to rozwiązanie może być przydatne dla wielu osób, tak jak było dla mnie.
źródło
Jeśli odpowiedzią jest bufor macierzy , wypróbuj to w ramach zdarzenia onsuccess w Ajax:
źródło
Poniżej znajduje się moje rozwiązanie do pobierania wielu plików w zależności od listy, która składa się z niektórych identyfikatorów i wyszukiwania w bazie danych, pliki zostaną określone i będą gotowe do pobrania - jeśli takie istnieją. Wzywam akcję C # MVC dla każdego pliku za pomocą Ajax.
I tak, jak powiedzieli inni, można to zrobić w jQuery Ajax. Zrobiłem to z sukcesem Ajax i zawsze wysyłam odpowiedź 200.
To jest klucz:
A to jest mój kod:
Następnie dzwoniąc:
C # MVC:
Dopóki zwrócisz odpowiedź 200, sukces w Ajaxie może z nią współpracować, możesz sprawdzić, czy plik faktycznie istnieje, czy nie, ponieważ poniższy wiersz w tym przypadku byłby fałszywy i możesz poinformować użytkownika o tym:
źródło
Potrzebowałem rozwiązania podobnego do tego @ alain-cruz, ale w nuxt / vue z wieloma pobraniami. Wiem, że przeglądarki blokują pobieranie wielu plików, a także mam interfejs API, który zwraca zestaw danych w formacie csv. Na początku miałem używać JSZip, ale potrzebowałem wsparcia IE, więc oto moje rozwiązanie. Jeśli ktoś może mi pomóc to poprawić, byłoby świetnie, ale jak dotąd działa dla mnie.
API zwraca:
page.vue:
źródło