Существующие решения предлагают либо одну, либо другую:
Но пока ни одно решение не имеет. Если вы хотите обоим, попробуйте следующее:
s = set(temp2)
temp3 = [x for x in temp1 if x not in s]
Тест производительности
import timeit
init = 'temp1 = list(range(100)); temp2 = [i * 2 for i in range(50)]'
print timeit.timeit('list(set(temp1) - set(temp2))', init, number = 100000)
print timeit.timeit('s = set(temp2);[x for x in temp1 if x not in s]', init, number = 100000)
print timeit.timeit('[item for item in temp1 if item not in temp2]', init, number = 100000)
Результаты:
4.34620224079 # ars' answer
4.2770634955 # This answer
30.7715615392 # matt b's answer
Метод, который я представил, а также сохранение порядок также (немного) быстрее, чем заданное вычитание, потому что он не требует построения ненужного набора. Разница в производительности будет более заметной, если первый список значительно длиннее второго, и если хеширование дорого. Вот второй тест, демонстрирующий это:
init = '''
temp1 = [str(i) for i in range(100000)]
temp2 = [str(i * 2) for i in range(50)]
'''
Результаты:
11.3836875916 # ars' answer
3.63890368748 # this answer (3 times faster!)
37.7445402279 # matt b's answer
Создайте форму, используйте метод POST, отправьте форму - нет необходимости в iframe. Когда страница сервера ответит на запрос, напишите заголовок ответа для типа mime файла, и он представит диалог загрузки - я сделал это несколько раз.
Вы хотите, чтобы контент- тип приложения / загрузка - просто найдите, как обеспечить загрузку для любого языка, который вы используете.
Я использовал этот файл FileSaver.js . В моем случае с файлами csv я сделал это (в coffescript):
$.ajax
url: "url-to-server"
data: "data-to-send"
success: (csvData)->
blob = new Blob([csvData], { type: 'text/csv' })
saveAs(blob, "filename.csv")
Я думаю, что для наиболее сложного случая данные должны обрабатываться должным образом. Под капотом FileSaver.js реализует тот же подход ответа Джонатан Аменд .
Чтобы получить Jonathan Amends ответ для работы в Edge I сделал следующие изменения:
var blob = typeof File === 'function'
? new File([this.response], filename, { type: type })
: new Blob([this.response], { type: type });
к этому
var f = typeof File+"";
var blob = f === 'function' && Modernizr.fileapi
? new File([this.response], filename, { type: type })
: new Blob([this.response], { type: type });
Я предпочел бы разместить это как комментарий, но у меня недостаточно репутации для этого
Это вопрос 3 года, но сегодня у меня такая же проблема. Я посмотрел ваше отредактированное решение, но я думаю, что он может пожертвовать производительностью, потому что он должен сделать двойной запрос. Поэтому, если кому-то нужно другое решение, которое не подразумевает двойную вызов службы, то это так, как я это сделал:
<form id="export-csv-form" method="POST" action="/the/path/to/file">
<input type="hidden" name="anyValueToPassTheServer" value="">
</form>
Эта форма используется только для вызова службы и избежания использования окна .место нахождения(). После этого вам просто нужно отправить форму из jquery, чтобы вызвать службу и получить файл. Это довольно просто, но таким образом вы можете сделать загрузку с помощью POST. Теперь я понял, что это может быть проще, если служба, которую вы вызываете, является GET, но это не мое дело.
Не сдавайтесь так быстро, потому что это можно сделать (в современных браузерах) с использованием частей FileAPI:
Редактировать 2017-09-28: Обновлено, чтобы использовать конструктор файлов, когда он доступен, поэтому работает в Safari> = 10.1.
Редактировать 2015-10-16: jQuery ajax не способен корректно обрабатывать двоичные ответы (не может установить responseType), поэтому лучше использовать простой вызов XMLHttpRequest.
var xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
if (this.status === 200) {
var filename = "";
var disposition = xhr.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, '');
}
var type = xhr.getResponseHeader('Content-Type');
var blob = typeof File === 'function'
? new File([this.response], filename, { type: type })
: new Blob([this.response], { type: type });
if (typeof window.navigator.msSaveBlob !== 'undefined') {
// IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed."
window.navigator.msSaveBlob(blob, filename);
} else {
var URL = window.URL || window.webkitURL;
var downloadUrl = URL.createObjectURL(blob);
if (filename) {
// use HTML5 a[download] attribute to specify filename
var a = document.createElement("a");
// safari doesn't support this yet
if (typeof a.download === 'undefined') {
window.location = downloadUrl;
} else {
a.href = downloadUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
}
} else {
window.location = downloadUrl;
}
setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup
}
}
};
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.send($.param(params));
Вот старая версия, использующая jQuery.ajax. Он может искажать двоичные данные, когда ответ преобразуется в строку некоторой кодировки.
$.ajax({
type: "POST",
url: url,
data: params,
success: function(response, status, xhr) {
// check for a filename
var filename = "";
var disposition = xhr.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, '');
}
var type = xhr.getResponseHeader('Content-Type');
var blob = new Blob([response], { type: type });
if (typeof window.navigator.msSaveBlob !== 'undefined') {
// IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed."
window.navigator.msSaveBlob(blob, filename);
} else {
var URL = window.URL || window.webkitURL;
var downloadUrl = URL.createObjectURL(blob);
if (filename) {
// use HTML5 a[download] attribute to specify filename
var a = document.createElement("a");
// safari doesn't support this yet
if (typeof a.download === 'undefined') {
window.location = downloadUrl;
} else {
a.href = downloadUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
}
} else {
window.location = downloadUrl;
}
setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup
}
}
});
Я вижу, что вы уже нашли решение, однако я просто хотел добавить некоторую информацию, которая может помочь кому-то, кто пытается достичь того же самого с большими запросами POST.
У меня была такая же проблема: пару недель назад действительно невозможно достичь «чистой» загрузки через AJAX, Filament Group создала плагин jQuery, который работает точно так, как вы уже узнали, он называется Загрузка файла jQuery , однако есть недостатки этой методики.
Если вы отправляете большие запросы через AJAX (скажем, файлы + 1 МБ), это будет отрицательно влиять на отзывчивость. В медленных подключениях к Интернету вам придется ждать много , пока не будет отправлен запрос, а также дождитесь загрузки файла. Это не похоже на мгновенный «щелчок» => «всплывающее» => «начало загрузки». Это больше похоже на «click» => «подождите, пока данные будут отправлены» => «wait for response» => «start start», из-за чего он будет выглядеть вдвое большим, потому что вам придется ждать отправки запроса через AJAX и вернуть его в качестве загружаемого файла.
Если вы работаете с небольшими размерами файлов & lt; 1MB, вы этого не заметите.
Мое приложение позволяет пользователям экспортировать изображения, динамически сгенерированные, эти изображения отправляются через запросы POST в формате base64 на сервер (это означает, что для больших файлов это невыносимо. является единственным возможным способом), затем обрабатывается и отправляется обратно пользователям в виде файлов .png, .jpg, base64 для изображений + 1 МБ огромны, поэтому пользователи вынуждены ждать больше, чем необходимо для начала загрузки файла. В медленных интернет-соединениях это может быть очень неприятно.
Моим решением для этого было временно записать файл на сервер, как только он будет готов, динамически создать ссылку на файл в виде кнопки, которая меняет между «Подождите ...» и «Загрузить», и в то же время напечатайте изображение base64 во всплывающем окне предварительного просмотра, чтобы пользователи могли «щелкнуть правой кнопкой мыши» и сохранить его. Это делает все время ожидания более приемлемым для пользователей, а также ускоряет работу.
Обновление 30 сентября 2014 года:
Месяцы прошли с тех пор, как я опубликовал это, наконец, я «Мы нашли лучший подход к ускорению работы при работе с большими строками base64. Теперь я храню строки base64 в базе данных (используя longtext или longblog fields), затем передаю свой идентификатор записи через файл загрузки jQuery, наконец, в файле сценария загрузки я запрашиваю базу данных с помощью этого идентификатора, чтобы вытащить строку base64 и передать ее функция загрузки.
Пример сценария загрузки:
<?php // Record ID $downloadID = (int)$_POST['id']; // Query Data (this example uses CodeIgniter) $data = $CI->MyQueries->GetDownload( $downloadID ); // base64 tags are replaced by [removed], so we strip them out $base64 = base64_decode( preg_replace('#\[removed\]#', '', $data[0]->image) ); // This example is for base64 images $imgsize = getimagesize( $base64 ); // Set content headers header('Content-Disposition: attachment; filename="my-file.png"'); header('Content-type: '.$imgsize['mime']); // Force download echo $base64; ?>
Я знаю, что это намного выше того, что задал ОП, однако я чувствовал, что это будет хорошо чтобы обновить мой ответ своими выводами. Когда я искал решения моей проблемы, я читал много потоков «Загрузка из AJAX POST», которые не дали мне ответа, который я искал, я надеюсь, что эта информация поможет кому-то найти что-то подобное.
jQuery File Download
перенаправляет меня только на URL. Я называю это так: jQuery.download("api/ide/download-this-file.php", {filePath: path2Down}, "POST");
.
– Kin
13 March 2017 в 21:00
Какой серверный язык вы используете? В моем приложении я могу легко загрузить файл из вызова AJAX, установив правильные заголовки в ответе PHP:
header("HTTP/1.1 200 OK");
header("Pragma: public");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
// The optional second 'replace' parameter indicates whether the header
// should replace a previous similar header, or add a second header of
// the same type. By default it will replace, but if you pass in FALSE
// as the second argument you can force multiple headers of the same type.
header("Cache-Control: private", false);
header("Content-type: " . $mimeType);
// $strFileName is, of course, the filename of the file being downloaded.
// This won't have to be the same name as the actual file.
header("Content-Disposition: attachment; filename=\"{$strFileName}\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . mb_strlen($strFile));
// $strFile is a binary representation of the file that is being downloaded.
echo $strFile;
Это будет фактически «перенаправление 'браузер на эту страницу загрузки, но, как сказал @ahren alread в своем комментарии, он не будет перемещаться от текущей страницы.
Все дело в настройке правильных заголовков, поэтому я уверен,
Предполагая, что вы уже знаете, как сделать вызов AJAX, вы можете найти подходящее решение для серверного языка, который вы используете, если это не PHP. на стороне клиента вы выполняете запрос AJAX на сервер. Затем сервер генерирует ссылку, с которой можно загрузить этот файл, например. URL 'forward', на который вы хотите указать. Например, сервер отвечает:
{
status: 1, // ok
// unique one-time download token, not required of course
message: 'http://yourwebsite.com/getdownload/ska08912dsa'
}
При обработке ответа вы вводите iframe
в своем теле и устанавливаете SRC iframe
в URL, который вы только что получили (например, используя jQuery для удобства этого примера):
$("body").append("<iframe src='" + data.message +
"' style='display: none;' ></iframe>");
Если вы установили правильные заголовки, как показано выше, iframe заставит диалоговое окно загрузки, не переведя браузер с текущей страницы.
Дополнительное дополнение по отношению к вашему вопросу; Я думаю, что лучше всегда возвращать JSON при запросе материала с помощью технологии AJAX. После того, как вы получили ответ JSON, вы можете решить, на какой стороне клиент, что с ним делать. Возможно, например, в дальнейшем вы хотите, чтобы пользователь нажал ссылку для загрузки на URL, а не на прямое скачивание, в вашей текущей настройке вам нужно будет обновить как клиент, так и серверную сторону, чтобы сделать это.
Как утверждали другие, вы можете создать и отправить форму для загрузки через запрос POST. Однако вам не нужно делать это вручную.
Одна действительно простая библиотека для выполнения именно этого - jquery.redirect . Он предоставляет API, похожий на стандартный метод jQuery.post
:
$.redirect(url, [values, [method, [target]]])
Вот мое решение, используя временную скрытую форму.
//Create an hidden form
var form = $('<form>', {'method': 'POST', 'action': this.href}).hide();
//Add params
var params = { ...your params... };
$.each(params, function (k, v) {
form.append($('<input>', {'type': 'hidden', 'name': k, 'value': v}));
});
//Make it part of the document and submit
$('body').append(form);
form.submit();
//Clean up
form.remove();
Обратите внимание, что я широко использую JQuery, но вы можете сделать то же самое с встроенным JS.
Вот как я получил эту работу https://stackoverflow.com/a/27563953/2845977
$.ajax({
url: '<URL_TO_FILE>',
success: function(data) {
var blob=new Blob([data]);
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download="<FILENAME_TO_SAVE_WITH_EXTENSION>";
link.click();
}
});
$.ajax({
url: '<URL_TO_FILE>',
success: download.bind(true, "<FILENAME_TO_SAVE_WITH_EXTENSION>", "<FILE_MIME_TYPE>")
});
Я столкнулся с той же проблемой и успешно ее разрешил.
«Опубликовать данные JSON на сервере и получить файл excel. Этот файл excel создается сервером и возвращается как ответ клиенту. Загрузите этот ответ в виде файла с пользовательским именем в браузере "
$("#my-button").on("click", function(){
// Data to post
data = {
ids: [1, 2, 3, 4, 5]
};
// Use XMLHttpRequest instead of Jquery $ajax
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
var a;
if (xhttp.readyState === 4 && xhttp.status === 200) {
// Trick for making downloadable link
a = document.createElement('a');
a.href = window.URL.createObjectURL(xhttp.response);
// Give filename you wish to download
a.download = "test-file.xls";
a.style.display = 'none';
document.body.appendChild(a);
a.click();
}
};
// Post data to URL which handles post request
xhttp.open("POST", excelDownloadUrl);
xhttp.setRequestHeader("Content-Type", "application/json");
// You should set responseType as blob for binary responses
xhttp.responseType = 'blob';
xhttp.send(JSON.stringify(data));
});
Вышеприведенный фрагмент просто выполняет следующие действия
Здесь нам нужно тщательно задать несколько вещей в на стороне сервера. Я установил несколько заголовков в Python Django HttpResponse. Вы должны установить их соответственно, если используете другие языки программирования.
# In python django code
response = HttpResponse(file_content, content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
Так как я загружаю xls (excel) здесь, я скорректировал contentType на один. Вам нужно установить его в соответствии с типом файла. Вы можете использовать эту технику для загрузки любых файлов.
см.: http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/ он вернет blob в качестве ответа, который затем может быть помещен в filesaver
Я хочу указать на некоторые трудности, возникающие при использовании метода в принятом ответе, т. е. с использованием сообщения формы:
В итоге я использовал метод сохранения файла на S3 и отправку предварительно подписанного URL для получения файла.
Для тех, кто ищет решение с угловой точки зрения, это сработало для меня:
$http.post(
'url',
{},
{responseType: 'arraybuffer'}
).then(function (response) {
var headers = response.headers();
var blob = new Blob([response.data],{type:headers['content-type']});
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "Filename";
link.click();
});