В 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, упомянутый в этом .