我目前有以下工作代码片段(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错误对象并使用它做一些事情。
如果请求成功,我怎么能避免发出两个请求?
"CONTENT-DISPOSITION" -> "attachment"
更新: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
});
在后端(我使用Play framework / Scala)
def myendpoint(onlyDoCheck: Boolean = false) = Action{implicit request =>
myForm.bindFromRequest.fold(
e => BadRequest(myErrors),
v => if(onlyDoCheck) Ok(simpleOkResponse) else Ok(doComputationgeneratefileandoutputfile)
)
}
答案 0 :(得分:7)
你能做的最好就是分割你的终点。
如果文件位于磁盘上且未自动生成且需要进行身份验证以进行身份验证,则可以将文件隐藏在正常端点后面,执行检查并使用X-Accel-Redirect
返回文件带有nginx的头文件或使用apache的X-Sendfile
。
免责声明:这不是最好的解决方案。正如@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中提到的answer插件。