You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 14:41:04