Допустим, у меня есть ссылки для скачивания файлов на моем сайте.
При нажатии на эти ссылки отправляется запрос AJAX на сервер, который возвращает URL-адрес с расположением файла.
Что я хочу сделать, так это указать браузеру загрузить файл после получения ответа. Есть ли портативный способ сделать это?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Я предлагаю сделать невидимый iframe на странице и установить его src на url, который вы получили с сервера - загрузка начнется без перезагрузки страницы.
Или вы можете просто установить текущий document.location.href на полученный URL-адрес. Но это может привести к тому, что пользователь увидит ошибку, если запрошенный документ на самом деле не существует.
Согласны с методами, упомянутыми maxnk, однако вы можете пересмотреть попытку автоматически заставить браузер загружать URL-адрес. Он может работать нормально для двоичных файлов, но для других типов файлов (текст, PDF, изображения, видео) браузер может захотеть отобразить его в окне (или IFRAME), а не сохранять на диск.
Если вам действительно нужно сделать вызов Ajax, чтобы получить окончательные ссылки для загрузки, как насчет использования DHTML для динамической записи ссылки для загрузки (из ответа ajax) на страницу? Таким образом, пользователь мог либо щелкнуть по нему, чтобы загрузить (если он был двоичным), либо просмотреть его в своем браузере, либо выбрать «Сохранить как» в ссылке, чтобы сохранить на диск. Это дополнительный щелчок, но у пользователя больше контроля.
Ах да, я забыл о небинарных файлах, спасибо. В качестве альтернативы может быть хорошим решением создать оболочку вокруг файлового потока с сервера и установить заголовок «Content-Disposition: attachment». Но подходит только для небольших файлов.
Или вы можете попытаться обмануть браузер, заставив его думать, что загружаемый файл является двоичным, попросив сервер отправить заголовок Content-Type как «application / octet-stream», независимо от фактического типа файла.
Internet Explorer 8 блокирует загрузку файлов всеми упомянутыми способами (iframe, window.location.href или даже «http-Equiv = REFRESH CONTENT»). «Чтобы защитить вашу безопасность, IE заблокировал загрузку файлов с этого сайта на ваш компьютер ...». Вы знаете способ подавить это предупреждение и начать загрузку, как, скажем, Firefox? Я проверил несколько сайтов: Skype, Google (с Picasa) и Download.com вызывает предупреждение при загрузке (потому что они показывают своего рода страницу с благодарностью). Спасибо за ваши мысли!
Установите заголовки для этого типа файла в htaccess.
Я бы посоветовал window.open() открыть всплывающее окно. Если это загрузка, окна не будет, и вы получите свой файл. Если есть 404 или что-то в этом роде, пользователь увидит его в новом окне (следовательно, его работа не будет беспокоить, но они все равно будут получать сообщение об ошибке).
это отлично работает, если вы имеете дело с ссылкой, нажатой пользователем (но тогда почему она вообще должна быть js?), она все равно столкнется с нарушением безопасности IE.
Если это ваше собственное серверное приложение, я предлагаю использовать следующий заголовок
Content-disposition: attachment; filename=fname.ext
Это заставит любой браузер загрузить файл и не отобразить его в окне браузера.
Просто вызовите window.location.href = new_url из своего javascript, и он перенаправит браузер на этот URL-адрес, так как пользователь ввел его в адресную строку.
Делаем так: Сначала добавьте этот скрипт.
<script type = "text/javascript">
function populateIframe(id,path)
{
var ifrm = document.getElementById(id);
ifrm.src = "download.php?path = "+path;
}
</script>
Поместите это там, где вы хотите кнопку загрузки (здесь мы используем только ссылку):
<iframe id = "frame1" style = "display:none"></iframe>
<a href = "javascript:populateIframe('frame1','<?php echo $path; ?>')">download</a>
Файл 'download.php' (должен быть размещен на вашем сервере) просто содержит:
<?php
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename = ".$_GET['path']);
readfile($_GET['path']);
?>
Поэтому, когда вы щелкаете ссылку, скрытый iframe получает / открывает исходный файл «download.php». С путем в качестве параметра получения. Думаем, это лучшее решение!
Следует отметить, что PHP-часть этого решения представляет собой простую демонстрацию и потенциально очень и очень небезопасна. Это позволяет пользователю загружать любой файл, а не только заранее определенный набор. Это означает, что они могут загружать части исходного кода самого сайта, возможно, содержащие учетные данные API и т. д.
@Fabio: if (!file_exists($path)) { header("HTTP/1.1 404 Not Found"); exit; } должен помочь
Есть ли способ для javascript узнать о ходе загрузки (или просто о том, завершен ли он)?
@camupod Я так не думаю. Если вам нужен прогресс загрузки, вам нужно использовать XmlHttpRequest Level 2. w3.org/TR/XMLHttpRequest/#event-xhr-progress
Что мешает пользователю просмотреть исходный код, получить URL-адрес для download.php, а затем перейти к yoursite.com/download.php?path=config.php, чтобы попытаться получить ваши пароли? Другими словами: пожалуйста, пожалуйста, не делай этого так.
@Grim ... Мне просто пришло в голову возможное решение, вы могли бы использовать относительный путь из вашего файла download.php, что-то вроде readfile ("../ public /".$_ GET ['path']); а затем все, что вам нужно сделать перед этим, это проверить, что $ _GET ['path'] нигде не содержит "..". Может это сработать? По общему признанию, это немного взлом, но быстрое небольшое решение?
Относительный путь может быть чем-то вроде /common/config.php. Думаю, вы могли бы убедиться, что первым символом не является '/', но держу пари, что есть еще много способов добраться туда.
Большое спасибо - без присланных заголовков я не мог заставить его работать ни в IE, ни в Chrome. Так что это решение отлично работает!
Следуя комментарию @Grim ..., он определенно прав, НЕ делайте этого таким образом. Сделайте ссылку iframe src непосредственно на файл и используйте .htaccess, чтобы установить информацию заголовка для этого конкретного типа файла.
@ Мрачный ... Какая безопасная альтернатива? Почему вы не отвечаете или не редактируете ответ ..?
Некоторые безопасные альтернативы: 1) Проверьте запрошенный путь по белому списку, 2) Создайте карту id => filepath и используйте вместо этого id.
Я создал Плагин загрузки файла jQuery (Демо с примерами) (GitHub) с открытым исходным кодом, который также может помочь в вашей ситуации. Он работает примерно так же, как iframe, но имеет несколько интересных функций, которые мне показались очень удобными:
Привет. Есть ли способ запретить Internet Explorer 8 блокировать загрузку? Информационная панель Internet Explorer запрашивает подтверждение загрузки, что приводит к перезагрузке страницы без загрузки, в результате чего пользователь должен еще раз щелкнуть ссылку для загрузки. заранее спасибо
Это как раз то, что мне нужно. Спасибо!
Читая ответы, включая принятый, я хотел бы указать на последствия для безопасности передачи пути непосредственно к файлу чтения через GET.
Некоторым это может показаться очевидным, но некоторые могут просто скопировать / вставить этот код:
<?php
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename = ".$_GET['path']);
readfile($_GET['path']);
?>
Итак, что произойдет, если я передам в этот скрипт что-то вроде «/ path / to / fileWithSecrets»? Данный скрипт с радостью отправит любой файл, к которому пользователь веб-сервера имеет доступ.
Пожалуйста, обратитесь к этому обсуждению, чтобы узнать, как это предотвратить: Как убедиться, что путь к файлу находится в заданном подкаталоге?
Свяжите напрямую с файлом в iframe и установите заголовки в htaccess.
Это должен быть комментарий, а не ответ.
Зачем вы делаете вещи на стороне сервера, когда все, что вам нужно, это перенаправить браузер на другой window.location.href?
Вот код, который анализирует? File = QueryString (взято из этого вопроса) и перенаправляет пользователя на этот адрес за 1 секунду (работает у меня даже в браузерах Android):
<script type = "text/javascript">
var urlParams;
(window.onpopstate = function () {
var match,
pl = /\+/g, // Regex for replacing addition symbol with a space
search = /([^&=]+)=?([^&]*)/g,
decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); },
query = window.location.search.substring(1);
urlParams = {};
while (match = search.exec(query))
urlParams[decode(match[1])] = decode(match[2]);
})();
(window.onload = function() {
var path = urlParams["file"];
setTimeout(function() { document.location.href = path; }, 1000);
});
</script>
Если в вашем проекте есть jQuery, обязательно удалите эти обработчики window.onpopstate и window.onload и сделайте все в $ (document) .ready (function () {});
Попробуйте эту библиотеку https://github.com/PixelsCommander/Download-File-JS, она более современна, чем все решения, описанные ранее, потому что использует атрибут «загрузка» и комбинацию методов для обеспечения наилучшего качества работы.
Объясняется здесь - http://pixelscommander.com/en/javascript/javascript-file-downliading-ignore-content-type/
Кажется, это идеальный фрагмент кода для начала загрузки на JavaScript.
Чтобы обойти недостаток безопасности в ответе, получившем наибольшее количество голосов, вы можете установить iframe src непосредственно в нужный файл (вместо промежуточного файла php) и установить информацию заголовка в файле .htaccess:
<Files *.apk>
ForceType application/force-download
Header set Content-Disposition attachment
Header set Content-Type application/vnd.android.package-archive
Header set Content-Transfer-Encoding binary
</Files>
Что касается главного ответа, у меня есть возможное решение проблемы безопасности.
<?php
if (isset($_GET['path'])){
if (in_array($_GET['path'], glob("*/*.*"))){
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename = ".$_GET['path']);
readfile($_GET['path']);
}
}
?>
Используя функцию glob () (я тестировал загружаемый файл по пути на одну папку выше загружаемого файла), я смог быстро создать массив файлов, которые «разрешено» загружать, и проверил переданный путь по нему. . Это не только гарантирует, что захватываемый файл не является конфиденциальным, но и одновременно проверяет наличие файлов.
~ Примечание: Javascript / HTML ~
HTML:
<iframe id = "download" style = "display:none"></iframe>
а также
<input type = "submit" value = "Download" onclick = "ChangeSource('document_path');return false;">
JavaScript:
<script type = "text/javascript">
<!--
function ChangeSource(path){
document.getElementByID('download').src = 'path_to_php?path=' + document_path;
}
-->
</script>
Верно, но это основывалось на верхнем ответе. Тем не менее, я добавлю аналогичное соединение JavaScript.
когда будет безопасно удалить iframe из DOM?