我正在开发一个Web应用程序,该应用程序在前端使用HTML +纯Javascript,并在后端使用Flask。应用程序将一些ID发送到服务器,服务器应将报告生成为PDF文件并将其发送回客户端。
我将Flask用于后端,并且创建了以下端点:
@app.route("/download_pdf", methods=['POST'])
def download_pdf():
if request.method == 'POST':
report_id = request.form['reportid']
print(report_id) //Testing purposes.
// do some stuff with report_id and generate a pdf file.
return send_file('/home/user/report.pdf', mimetype='application/pdf', as_attachment=True)
// I already tried different values for mimetype and as_attachment=False
从命令行中,我可以测试端点并获得正确的文件,服务器控制台将按预期方式打印123 report_id:
curl --form reportid=123 http://localhost:5000/download_pdf >> output.pdf
对于前端,我创建了一个调用Javascript函数的按钮:
<button id=pdf_button onclick="generatePdf()"> PDF </button>
Javascript函数如下所示:
function generatePdf(){
var report_list = document.getElementById("report_list")
if (report_list.selectedIndex < 0){
alert("Please, select a report.");
}else{
var req = new XMLHttpRequest();
req.open("POST", "/download_pdf", true);
req.responseType = "document";
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
req.onreadystatechange = function(){
console.log(req.readyState)
console.log(req.status)
console.log(req.response)
var link = document.createElement('a')
link.href = req.response;
link.download="report.pdf"
link.click()
}
var selected_value = report_list.options[report_list.selectedIndex].value;
var params="reportid="+selected_value;
req.send(params);
}
};
req.response在这种情况下为null。但是,对端点的调用已正确完成,因为后端控制台按预期输出了report_id。
已经尝试:
最后,Firefox控制台在按下相关按钮后会显示这6条消息(请注意前面代码中的console.log()调用):
2
0
null
4
0
null
当按下按钮时,似乎Javascript函数已被调用两次。
我的目标是下载PDF。我不知道我在做什么错;非常感谢您的帮助。
答案 0 :(得分:0)
您的Ajax设置错误,应该像这样
req.open("POST", "/download_pdf", true);
req.responseType = "blob";
req.onreadystatechange = function() {
console.log(req.readyState)
console.log(req.status)
const blob = new Blob([req.response]);
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a')
link.href = url
link.download = "report.pdf"
link.click()
}
响应类型应为blob,当您获得响应时,将其解析为blob。一段时间后,删除链接
setTimeout(() => {
window.URL.revokeObjectURL(url);
link.remove();
}, 100);
答案 1 :(得分:0)
最后,我发现了问题所在,并将其发布以备记录。
我以为这没有关系,但是调用Javascript函数的<button>
位于<form>
内部。我检查了对端点的调用完成之前表单是否已更新,从而导致调用提前完成。
如果其他人需要此示例,则最终代码的摘要如下:
HTML(选择和按钮都不属于<form>
的一部分):
<select id="report_list" size=20> ... </select>
...
<button id="pdf_button" onclick="generatePdf()"> PDF </button>
Javascript:
function generatePdf(){
var report_list = document.getElementById("report_list");
var req = XMLHttpRequest();
var selected_value = report_list.options[report_list.selectedIndex].value;
req.open("POST", "/reports/"+selected_value+"/pdf", true);
req.responseType = "blob";
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
req.onreadystatechange = function(){
if (this.readyState == 4 && this.status == 200){
var blob = new Blob([this.response], {type: "application/pdf"});
var url = window.URL.createObjectURL(blob);
var link = document.createElement('a');
document.body.appendChild(link);
link.style = "display: none";
link.href = url;
link.download = "report.pdf";
link.click();
setTimeout(() => {
window.URL.revokeObjectURL(url);
link.remove(); } , 100);
}
};
req.send();
}
烧瓶:
@app.route("/reports/<id>/pdf", methods=['POST'])
def get_pdf(id):
if request.method == 'POST':
return send_file(get_pdf_path(id), mimetype='application/pdf')
我不确定这是否是完成此任务的最好或更优雅的方法,但到目前为止,它对我还是有用的。