В Javascript, как я могу перенаправить ответ Ajax в расположение окна
В настоящее время у меня есть следующий фрагмент кода (angular, но применим к любой инфраструктуре JS):
var url = '/endpoint/to/my/file';
$http({
method: 'GET',
url: url
})
.success(function(jdata) {
window.location = url;
})
.error(function(je){
// display errors on page
});
Вышеупомянутый вызывается после того, как форма была завершена, и пользователь нажал кнопку "отправить" (реальная ситуация немного сложнее, но это та же идея). Я выполняю проверку формы асинхронно, поэтому перезагрузка страницы не выполняется.
Если запрос успешный, возвращает двоичный файл (файл pdf), если он не является успешным, запрос возвращает 400 BadRequest с ошибками, отформатированными в JS. Итак, что я делаю, в случае успеха я перенаправляю на тот же URL-адрес, чтобы иметь PDF файл, иначе я получаю объект ошибки JSON и что-то с ним делаю.
Как я могу воздержаться от выполнения двух запросов, если запросы успешны?
- Примечание1: на стороне сервера я хотел бы сохранить только один маршрут, который сделает все, проверьте + вернуть PDF
- Примечание2: текущая ситуация на мой взгляд довольно аккуратная, так как у меня есть асинхронная проверка формы, и если файл успешно загружен непосредственно в браузере, так как у меня есть
"CONTENT-DISPOSITION" -> "attachment"
в заголовке HTTP успешного ответа
Обновление: дополнительная информация об архитектуре по просьбе Эмиля:
В моем случае использования у меня есть одна конечная точка, которая проверяет ввод (и другие внешние требования). По соображениям безопасности я не могу вывести PDF файл, если все требования не выполнены, поэтому я должен выполнить проверку перед отправкой файла (файл автоматически создается) в любом случае. Таким образом, наличие двух конечных точек просто избыточно и добавит ненужную сложность.
Во время написания я думаю, что альтернативным решением может быть передача аргумента на конечной точке во время проверки, так что если он будет успешным, он остановится и не сгенерирует PDF, а затем перенаправится на ту же конечную точку без флага, который будет вывод PDF.
Поэтому я делаю проверку дважды, но только загружаю (и генерирую - это ресурсоемкий) файл только один раз, и у меня есть только одна конечная точка...
Здесь адаптированный код:
var url = '/endpoint/to/my/file';
$http({
method: 'GET',
url: url+'?check'
})
.success(function(jdata) {
window.location = url;
})
.error(function(je){
// display errors on page
});
На стороне сервера (я использую платформу воспроизведения / Scala)
def myendpoint(onlyDoCheck: Boolean = false) = Action{implicit request =>
myForm.bindFromRequest.fold(
e => BadRequest(myErrors),
v => if(onlyDoCheck) Ok(simpleOkResponse) else Ok(doComputationgeneratefileandoutputfile)
)
}
Ответы
Ответ 1
Реальная сделка
Лучшее, что вы можете сделать, это разделить конечную точку.
- Один для формы и удобства ошибок без обновления.
- Затем, при успехе, перенаправляйтесь на другую конечную точку, которая загружает только файл.
Если файл был на диске и не был автоматически сгенерирован и должен быть аутентифицирован для загрузки, вы можете скрыть файл за нормальной конечной точкой, выполнить проверки и вернуть файл с помощью заголовка X-Accel-Redirect
с nginx или X-Sendfile
с помощью apache.
Хак
Отказ от ответственности: это скорее взлом, чем лучшее решение. Как упоминалось @Iceman, Safari, IE, Safari-iOS, Opera-mini и некоторые подобные браузеры не поддерживают эту конкретную спецификацию.
В конечной точке на стороне сервера, если файл доступен без ошибок, вы можете установить заголовок в тип содержимого файла (например, 'application/pdf'
), чтобы загрузка запустилась автоматически.
Если есть ошибки, не устанавливайте заголовок и не возвращайте json ошибок, чтобы информировать пользователя через javascript.
Поскольку мы не знаем, что позади, здесь пример python (Django):
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename=your_filename.pdf'
response.write(repport.printReport(participantId))
return response
Вы можете обработать ответ в обратном вызове ajax:
$.ajax({
url: 'endpoint.php',
success: function(data) {
var blob = new Blob([data]);
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "filename.pdf";
link.click();
}
});
Вы также можете попробовать плагин jQuery fileDownload, упомянутый в этом .