SpringBoot生成PDF无法在浏览器下载的问题求助
问题分析与解决方案
核心原因:浏览器通过AJAX/fetch/axios这类脚本发起的请求获取PDF时,不会自动触发下载弹窗——这类请求的响应会直接返回给脚本,浏览器默认不会解析Content-Disposition: attachment头,这就是你看到Chrome显示PDF源码的原因。而Postman能正常下载,是因为它会自动识别并处理这个响应头。
以下是两种可行的解决方式:
方案1:前端手动处理响应内容(推荐)
通过脚本将后端返回的Blob数据转换成可下载的链接,手动触发下载:
Fetch API 示例
document.getElementById('downloadBtn').addEventListener('click', async () => { const reportId = '目标报表ID'; try { const res = await fetch(`/download/generateReport/${reportId}`, { method: 'POST', // 若需携带token等请求头,自行添加 headers: { 'Authorization': 'Bearer ' + yourToken } }); const blob = await res.blob(); const downloadUrl = window.URL.createObjectURL(blob); // 创建临时a标签触发下载 const a = document.createElement('a'); a.href = downloadUrl; // 从响应头解析文件名(也可直接指定) const disposition = res.headers.get('Content-Disposition'); a.download = disposition?.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)[1].replace(/['"]/g, '') || 'FavoriteReport.pdf'; document.body.appendChild(a); a.click(); // 清理资源 window.URL.revokeObjectURL(downloadUrl); document.body.removeChild(a); } catch (err) { console.error('下载失败:', err); } });
Axios 示例
axios.post(`/download/generateReport/${reportId}`, {}, { responseType: 'blob' // 必须设置,否则会拿到乱码文本 }) .then(res => { const blob = new Blob([res.data], { type: 'application/pdf' }); const downloadUrl = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = downloadUrl; const disposition = res.headers['content-disposition']; a.download = disposition?.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)[1].replace(/['"]/g, '') || 'FavoriteReport.pdf'; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(downloadUrl); document.body.removeChild(a); }) .catch(err => console.error('下载失败:', err));
方案2:用普通表单提交(无需前端脚本)
如果不想修改前端脚本逻辑,可让前端通过表单POST提交请求,浏览器会自动解析Content-Disposition头并触发下载:
<form action="/download/generateReport/目标报表ID" method="POST"> <!-- 若需携带额外参数,添加hidden输入框 --> <button type="submit">下载报表</button> </form>
后端代码验证
你的后端代码配置本身没有问题:
produces = "application/pdf"确保了响应Content-Type正确Content-Disposition: attachment头设置正确Access-Control-Expose-Headers: *允许前端读取响应头(包含Content-Disposition)
只需配合前端的请求方式调整即可解决问题。
内容的提问来源于stack exchange,提问作者likepickle
相关产品推荐
相关产品推荐

