Mam działanie Struts2 po stronie serwera do pobierania plików.
<action name="download" class="com.xxx.DownAction">
<result name="success" type="stream">
<param name="contentType">text/plain</param>
<param name="inputName">imageStream</param>
<param name="contentDisposition">attachment;filename={fileName}</param>
<param name="bufferSize">1024</param>
</result>
</action>
Jednak gdy wywołuję akcję za pomocą jQuery:
$.post(
"/download.action",{
para1:value1,
para2:value2
....
},function(data){
console.info(data);
}
);
w Firebug widzę, że dane są pobierane za pomocą strumienia binarnego . Zastanawiam się, jak otworzyć okno pobierania pliku, w którym użytkownik może zapisać plik lokalnie?
Odpowiedzi:
Aktualizacja nowoczesnych przeglądarek 2019
Takie podejście polecam teraz z kilkoma zastrzeżeniami:
2012 Oryginalne podejście oparte na jQuery / iframe / Cookie
Bluish ma w tym całkowitą rację, nie można tego zrobić przez Ajax, ponieważ JavaScript nie może zapisywać plików bezpośrednio na komputerze użytkownika (ze względów bezpieczeństwa). Niestety, wskazując główne okno adresu URL na pobierany plik oznacza, że masz niewielką kontrolę nad tym, co odczuwa użytkownik w momencie pobierania pliku.
Stworzyłem jQuery File Download, który pozwala na uzyskanie „podobnego do Ajaxa” pobierania plików wraz z wywołaniami zwrotnymi OnSuccess i OnFailure, aby zapewnić lepszą obsługę. Spójrz na mój post na blogu na temat typowego problemu, który rozwiązuje wtyczka, i niektóre sposoby jej używania, a także demonstrację pobierania pliku jQuery w akcji . Oto źródło
Oto prosta wersja demonstracyjna przypadku użycia źródła wtyczek z obietnicami. Strona demonstracyjna zawiera również wiele innych przykładów „lepszego UX”.
W zależności od przeglądarek, które chcesz obsługiwać, możesz użyć https://github.com/eligrey/FileSaver.js/, co pozwala na bardziej jednoznaczną kontrolę niż metoda pobierania pliku jQuery.
źródło
Nikt nie opublikował tego rozwiązania @ Pekka ... więc opublikuję to. To może komuś pomóc.
Nie musisz tego robić przez Ajax. Po prostu użyj
źródło
window.open(<url>, '_blank');
aby upewnić się, że pobieranie nie zastąpi bieżącej zawartości przeglądarki (niezależnie od nagłówka Content-Disposition).POST
zapytania.Możesz z HTML5
Uwaga: Zwracane dane pliku MUSZĄ być zakodowane w standardzie base64, ponieważ nie można kodować danych binarnych JSON
W mojej
AJAX
odpowiedzi mam strukturę danych, która wygląda następująco:Oznacza to, że mogę wykonać następujące czynności, aby zapisać plik przez AJAX
Funkcja base64ToBlob została wzięta stąd i musi być używana zgodnie z tą funkcją
Jest to dobre, jeśli serwer wysyła dane do zapisania. Jednak nie do końca opracowałem sposób implementacji kreacji zastępczej HTML4
źródło
a.click()
Nie wydają się działać w Firefoksie ... jakiś pomysł?a
revokeObjectURL
document.body.appendChild(a)
var bytechars = atob(base64)
generuje błądJavaScript runtime error: InvalidCharacterError
. Używam Chrome w wersji 75.0.3770.142, ale nie wiem, co tu jest nie tak.1. Agnostyk ramowy: pobieranie pliku serwletu jako załącznika
2. Struts2 Framework: Akcja pobiera plik jako załącznik
Lepiej byłoby użyć
<s:a>
tagu wskazującego OGNL na adres URL utworzony za pomocą<s:url>
tagu:W powyższych przypadkach musisz napisać nagłówek Content-Disposition w odpowiedzi , określając, że plik musi zostać pobrany (
attachment
), a nie otwarty przez przeglądarkę (inline
). Ci potrzebne do określenia typu zawartości też, a może chcesz dodać nazwę pliku i długość (w pomocy przeglądarki rysunek realistyczny progressbar).Na przykład podczas pobierania pliku ZIP:
Dzięki Struts2 (chyba że używasz akcji jako serwletu, na przykład włamania do bezpośredniego przesyłania strumieniowego ), nie musisz pisać niczego bezpośrednio w odpowiedzi; wystarczy użyć typu wyniku Stream i skonfigurowanie go w struts.xml będzie działać: PRZYKŁAD
3. Framework agnostic (framework / Struts2): otwieranie pliku serwletu (/ Action) w przeglądarce
Jeśli chcesz otworzyć plik w przeglądarce, zamiast go pobierać, ustawianie zawartości musi być ustawione na wartość wbudowaną , ale celem nie może być bieżąca lokalizacja okna; musisz kierować reklamy do nowego okna utworzonego przez javascript,
<iframe>
na stronie lub nowego okna utworzonego w locie za pomocą „przedyskutowanego” celu = „_ puste”:źródło
too long url
błąd.Prostym sposobem, aby przeglądarka pobierała plik, jest takie żądanie:
Spowoduje to otwarcie okna pobierania przeglądarki.
źródło
Stworzyłem niewiele funkcji jako rozwiązanie obejścia (zainspirowane wtyczką @JohnCulviner):
Demo ze zdarzeniem kliknięcia:
źródło
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 dokładnie 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
HTMLAnchorElement.download
, myślę o połączeniu go z zastrzeżoną metodą msSaveOrOpenBlob .Ok, w oparciu o kod ndpu, oto ulepszona (jak sądzę) wersja ajax_download; -
Użyj tego w ten sposób; -
Parametry są wysyłane jako odpowiednie parametry pocztowe, jakby pochodziły z danych wejściowych, a nie jako ciąg zakodowany w formacie json, jak w poprzednim przykładzie.
PRZESTROGA: Uważaj na możliwość zmiennego wstrzykiwania tych form. Może istnieć bezpieczniejszy sposób kodowania tych zmiennych. Ewentualnie rozważ ich ucieczkę.
źródło
Uncaught SecurityError: Blocked a frame with origin "http://foo.bar.com" from accessing a frame with origin "null". The frame requesting access has a protocol of "http", the frame being accessed has a protocol of "data". Protocols must match.
@ResourceMapping() public void downloadFile(final ResourceRequest request, final ResourceResponse response, @ModelAttribute("downForm") FormModel model)
ale to nie działa ..Oto co zrobiłem, czysty JavaScript i HTML. Nie przetestowałem tego, ale powinno to działać we wszystkich przeglądarkach.
źródło
źródło
download
atrybutu, więc plik będzie miał nazwę „Nieznany”W Rails robię to w ten sposób:
Sztuką jest window.location część. Metoda kontrolera wygląda następująco:
źródło
Posługiwać się
window.open
https://developer.mozilla.org/en-US/docs/Web/API/Window/openNa przykład możesz umieścić ten wiersz kodu w module obsługi kliknięć:
Otworzy się nowa karta (z powodu nazwy okna „_blank”) i ta karta otworzy adres URL.
Twój kod po stronie serwera powinien również mieć coś takiego:
W ten sposób przeglądarka powinna poprosić użytkownika o zapisanie pliku na dysku, zamiast tylko pokazywania mu pliku. Spowoduje to również automatyczne zamknięcie właśnie otwartej karty.
źródło
Próbuję pobrać plik CSV, a następnie zrobić coś po zakończeniu pobierania. Więc muszę zaimplementować odpowiednią
callback
funkcję.Używanie
window.location="..."
nie jest dobrym pomysłem, ponieważ nie mogę obsługiwać programu po zakończeniu pobierania. Coś w tym stylu, zmień nagłówek, aby nie był to dobry pomysł.fetch
jest dobrą alternatywą, jednak nie obsługuje IE 11 . Iwindow.URL.createObjectURL
nie może obsługiwać IE 11. Możesz to sprawdzić .To jest mój kod, jest podobny do kodu Shahrukh Alam. Ale powinieneś uważać, aby nie
window.URL.createObjectURL
doprowadzić do wycieków pamięci. Można odnieść to . Po nadejściu odpowiedzi dane zostaną zapisane w pamięci przeglądarki. Więc zanim klikniesza
link, plik został pobrany. Oznacza to, że po pobraniu możesz zrobić wszystko.źródło
Jak pobrać plik po otrzymaniu go przez AJAX
Jest to wygodne, gdy plik jest tworzony przez długi czas i musisz pokazać PRELOADER
Przykład podczas przesyłania formularza internetowego:
Opcjonalne funkcje zostały zakomentowane w celu uproszczenia przykładu.
Nie ma potrzeby tworzenia plików tymczasowych na serwerze.
W jQuery v2.2.4 OK. W starej wersji wystąpi błąd:
źródło
filename.match(/filename=(.*)/)[1]
(bez podwójnych cudzysłowów i znaku zapytania) - regex101.com/r/2AsD4y/2 . Twoje rozwiązanie było jednak jedynym rozwiązaniem, które działało po wielu poszukiwaniach.Dodanie jeszcze kilku rzeczy do powyższej odpowiedzi na pobranie pliku
Poniżej znajduje się kod java spring, który generuje bajt Array
Teraz w kodzie javascript za pomocą FileSaver.js, możesz pobrać plik z poniższym kodem
Powyższe spowoduje pobranie pliku
źródło
Ok, więc oto działający kod podczas korzystania z MVC i pobierania pliku z kontrolera
powiedzmy, że masz tablicę bajtów do zadeklarowania i wypełnienia, jedyne, co musisz zrobić, to użyć funkcji File (using System.Web.Mvc)
a następnie w tym samym kontrolerze dodaj te 2 funkcje
a następnie będziesz mógł zadzwonić do kontrolera, aby pobrać i uzyskać oddzwonienie „sukces” lub „niepowodzenie”
źródło
Znalazłem poprawkę, która chociaż tak naprawdę nie używa ajax, pozwala na użycie wywołania javascript w celu zażądania pobrania, a następnie otrzymania oddzwonienia, gdy pobieranie faktycznie się rozpocznie. Uważam to za pomocne, jeśli łącze uruchamia skrypt po stronie serwera, który zajmuje trochę czasu, aby skomponować plik przed wysłaniem. abyś mógł ostrzec ich o przetwarzaniu, a następnie, kiedy w końcu wyśle plik, usuń powiadomienie o przetwarzaniu. dlatego chciałem spróbować załadować plik za pośrednictwem ajax, aby na początku zdarzyć się zdarzenie, gdy plik zostanie zażądany, a inne, gdy rozpocznie się pobieranie.
js na pierwszej stronie
iframe
następnie drugi plik:
Myślę, że istnieje sposób na odczytanie danych za pomocą js, więc nie byłoby potrzebne php. ale nie wiem tego od ręki, a serwer, którego używam, obsługuje PHP, więc to działa dla mnie. pomyślałem, że podzielę się tym na wypadek, gdyby to komukolwiek pomogło
źródło
Jeśli chcesz skorzystać z pobierania plików jQuery, zwróć uwagę na to dla IE. Musisz zresetować odpowiedź, aby nie została pobrana
Twoje działanie można wdrożyć,
ServletResponseAware
aby uzyskać dostępgetServletResponse()
źródło
Pewne jest, że nie można tego zrobić za pośrednictwem połączenia Ajax.
Istnieje jednak obejście.
Kroki :
Jeśli używasz form.submit () do pobierania pliku, możesz:
Jest to pomocne w przypadku, gdy chcesz zdecydować, czy plik ma zostać pobrany po utworzeniu form.submit (), np .: może wystąpić przypadek, w którym w formularzu form.submit () występuje wyjątek po stronie serwera, a zamiast tego awarii, może być konieczne wyświetlenie niestandardowego komunikatu po stronie klienta, w takim przypadku ta implementacja może pomóc.
ź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
źródło
To działa tak dobrze w każdej przeglądarce (używam rdzenia asp.net)
źródło
Długo walczyłem z tym problemem. Wreszcie zaproponowana tutaj elegancka biblioteka zewnętrzna pomogła mi.
źródło