React前端调用DRF API实现带JWT验证的PDF下载方案咨询
DRF+React 带权限校验的PDF下载实现方案
一、后端(DRF)配置
1. 接口权限控制与用户信息注入
给生成PDF的视图类添加IsAuthenticated权限,确保仅登录用户可访问;同时在视图中直接通过request.user获取当前登录用户信息,注入到PDF生成逻辑里。
示例代码:
from rest_framework.permissions import IsAuthenticated from rest_framework.views import APIView from xhtml2pdf import pisa from django.http import HttpResponse class GeneratePDFView(APIView): permission_classes = [IsAuthenticated] # 限制仅登录用户访问 def get(self, request): # 获取当前登录用户的信息 current_user = request.user # 构造带用户信息的HTML模板 html_content = f""" <html> <body> <h2>个人专属报告</h2> <p>用户名:{current_user.username}</p> <p>注册邮箱:{current_user.email}</p> <!-- 其他PDF内容 --> </body> </html> """ # 配置PDF响应头,触发浏览器下载 response = HttpResponse(content_type='application/pdf') response['Content-Disposition'] = f'attachment; filename="user_{current_user.id}_report.pdf"' # 生成PDF并写入响应 pisa_status = pisa.CreatePDF(html_content, dest=response) if pisa_status.err: return HttpResponse('PDF生成失败', status=500) return response
2. 确保JWT认证生效
在DRF的settings.py中配置JWT认证类,让接口能识别请求头中的Token:
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework_simplejwt.authentication.JWTAuthentication', ], }
二、前端(React)实现
前端需要发送带JWT Token的API请求,接收二进制Blob数据后手动触发浏览器下载。
1. Axios实现示例
import axios from 'axios'; const downloadUserPDF = async () => { try { const token = localStorage.getItem('access_token'); const response = await axios.get('/api/generate-pdf/', { headers: { 'Authorization': `Bearer ${token}` // 携带JWT Token }, responseType: 'blob' // 必须指定响应类型为Blob }); // 生成Blob URL并创建下载链接 const blobUrl = window.URL.createObjectURL(new Blob([response.data])); const downloadLink = document.createElement('a'); downloadLink.href = blobUrl; // 从响应头提取文件名(也可自定义) const contentDisposition = response.headers['content-disposition']; let filename = 'user_report.pdf'; if (contentDisposition) { const matchResult = contentDisposition.match(/filename="?([^"]+)"?/); filename = matchResult?.[1] || filename; } downloadLink.setAttribute('download', filename); document.body.appendChild(downloadLink); downloadLink.click(); // 清理资源 document.body.removeChild(downloadLink); window.URL.revokeObjectURL(blobUrl); } catch (error) { console.error('PDF下载失败:', error); // 处理未授权情况,比如跳转登录页 if (error.response?.status === 401) { window.location.href = '/login'; } } };
2. 原生Fetch实现示例
const downloadUserPDF = async () => { try { const token = localStorage.getItem('access_token'); const response = await fetch('/api/generate-pdf/', { method: 'GET', headers: { 'Authorization': `Bearer ${token}` } }); if (!response.ok) { throw new Error(`请求错误:${response.status}`); } const blob = await response.blob(); const blobUrl = window.URL.createObjectURL(blob); const downloadLink = document.createElement('a'); downloadLink.href = blobUrl; // 提取文件名 const contentDisposition = response.headers.get('content-disposition'); let filename = 'user_report.pdf'; if (contentDisposition) { const matchResult = contentDisposition.match(/filename="?([^"]+)"?/); filename = matchResult?.[1] || filename; } downloadLink.download = filename; document.body.appendChild(downloadLink); downloadLink.click(); // 清理资源 document.body.removeChild(downloadLink); window.URL.revokeObjectURL(blobUrl); } catch (error) { console.error('PDF下载失败:', error); if (error.message.includes('401')) { window.location.href = '/login'; } } };
关键注意事项
- 后端必须设置
Content-Disposition响应头为attachment类型,否则前端无法识别为下载文件。 - 前端请求必须指定响应类型为Blob,否则会拿到乱码的文本内容。
- 需处理401未授权的异常情况,引导用户登录。
内容的提问来源于stack exchange,提问作者Ritankar Bhattacharjee
相关产品推荐
相关产品推荐

