在Javascript中如何在窗口位置重定向Ajax响应

Joh*_*ohn 2 javascript

我目前有以下工作代码(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
});
Run Code Online (Sandbox Code Playgroud)

在表单完成并且用户点击"提交"之后调用上面的内容(实际情况比这更复杂,但它是相同的想法).我异步进行表单检查,因此没有页面重新加载.

如果请求成功,则返回二进制文件(pdf文件),如果不成功,请求将返回400 BadRequest,并在JS中格式化错误.所以我做的是,如果成功,我重定向到相同的URL以获得PDF,否则我得到JSON错误对象并用它做一些事情.

如果请求成功,我怎么能避免提出两个请求?

  • 注1:在后端,我想只保留一条完成所有操作的路线,检查+返回PDF
  • 注2:我认为目前的情况非常简洁,因为我有一个异步表单检查,如果成功,文件直接在浏览器中下载,因为我"CONTENT-DISPOSITION" -> "attachment"在成功响应的HTTP头中

更新:有关Emile请求的体系结构的其他信息:在我的用例中,我有一个端点检查输入(和其他外部要求).出于安全原因,如果不满足所有要求,我将无法输出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
});
Run Code Online (Sandbox Code Playgroud)

在后端(我使用Play框架/ Scala)

def myendpoint(onlyDoCheck: Boolean = false) = Action{implicit request =>
   myForm.bindFromRequest.fold(
     e => BadRequest(myErrors),
     v => if(onlyDoCheck) Ok(simpleOkResponse) else  Ok(doComputationgeneratefileandoutputfile)
   )
}
Run Code Online (Sandbox Code Playgroud)

Emi*_*ron 7

真正的交易

您可以做的最好的事情是拆分端点.

  1. 一个是形式和方便有错误而不刷新.
  2. 然后,成功时,重定向到仅下载文件的另一个端点.

如果文件位于磁盘上且未自动生成并且需要进行身份验证以进行下载,则可以将文件隐藏在正常端点后面,执行检查,并使用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
Run Code Online (Sandbox Code Playgroud)

您可以在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();
    }
});
Run Code Online (Sandbox Code Playgroud)

您还可以尝试本答案中提到的jQuery fileDownload插件.