ASP.NET Core MVC:通过Ajax调用Rotativa并在新标签页打开PDF问题
解决ASP.NET Core MVC中通过POST+防伪令牌调用Rotativa导出PDF并新标签页打开的问题
核心问题原因
直接用Ajax接收Rotativa返回的PDF二进制流时,若未指定正确的响应类型,浏览器会将二进制数据解析为文本,导致显示乱码。需要通过Blob处理或动态表单提交两种方式解决。
步骤1:修改控制器方法
将原GET接口改为POST,添加防伪令牌验证,接收复杂参数:
[HttpPost("ExportRotativa")] [ValidateAntiForgeryToken] public async Task<IActionResult> ExportRotativa([FromBody] YourComplexParamModel paramModel) { // 根据传入参数获取报表数据 DbImpendingMedicareReportViewModel model = await _IfunctionsUtil.ImpendingMedicareElibigibilityReport(paramModel); model.uIElementModel = SessionManagerUtil.GetUIElement(HttpContext.Session); // 配置PDF导出选项 var pdfResult = new ViewAsPdf("NewPdf", model) { FileName = "Medicare_Eligibility_Report.pdf", PageSize = Rotativa.AspNetCore.Options.Size.A4 }; return pdfResult; }
说明:
YourComplexParamModel是你定义的复杂参数模型类,需与前端传入的参数结构匹配- 若使用表单提交而非JSON,可将
[FromBody]改为[FromForm],并调整参数接收方式
步骤2:前端实现方案
方案一:Ajax+Blob处理(推荐,支持复杂JSON参数)
通过Ajax请求获取Blob格式的PDF流,创建临时URL在新标签页打开:
<!-- 确保页面包含防伪令牌(ASP.NET Core Razor页面默认自动生成,或手动添加) --> @Html.AntiForgeryToken() <button id="exportPdfBtn">导出PDF</button> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script> $('#exportPdfBtn').click(function() { // 获取防伪令牌值 const antiForgeryToken = $('input[name="__RequestVerificationToken"]').val(); // 构造复杂参数 const complexParams = { StartDate: $('#StartDate').val(), EndDate: $('#EndDate').val(), DepartmentIds: [101, 102, 103], IncludeInactive: $('#IncludeInactive').is(':checked') }; $.ajax({ url: '/ExportRotativa', type: 'POST', headers: { 'RequestVerificationToken': antiForgeryToken }, data: JSON.stringify(complexParams), contentType: 'application/json', responseType: 'blob', // 关键:指定响应为二进制Blob success: function(blob) { // 创建临时URL指向Blob数据 const pdfUrl = window.URL.createObjectURL(blob); // 在新标签页打开PDF window.open(pdfUrl); // 延迟释放URL资源,避免内存泄漏 setTimeout(() => window.URL.revokeObjectURL(pdfUrl), 100); }, error: function(xhr) { console.error('PDF导出失败:', xhr.responseText); alert('导出失败,请检查参数或重试'); } }); }); </script>
方案二:动态表单提交(兼容旧浏览器,适合简单参数)
通过动态创建隐藏表单提交POST请求,让浏览器直接处理PDF响应:
@Html.AntiForgeryToken() <button id="exportPdfBtn">导出PDF</button> <script> $('#exportPdfBtn').click(function() { const antiForgeryToken = $('input[name="__RequestVerificationToken"]').val(); const complexParams = { StartDate: document.getElementById('StartDate').value, EndDate: document.getElementById('EndDate').value }; // 创建隐藏表单 const form = document.createElement('form'); form.method = 'POST'; form.action = '/ExportRotativa'; form.target = '_blank'; // 指定在新标签页打开 // 添加防伪令牌 const tokenInput = document.createElement('input'); tokenInput.type = 'hidden'; tokenInput.name = '__RequestVerificationToken'; tokenInput.value = antiForgeryToken; form.appendChild(tokenInput); // 添加复杂参数(转为JSON字符串提交) const paramInput = document.createElement('input'); paramInput.type = 'hidden'; paramInput.name = 'paramModel'; paramInput.value = JSON.stringify(complexParams); form.appendChild(paramInput); // 提交表单并移除 document.body.appendChild(form); form.submit(); document.body.removeChild(form); }); </script>
对应控制器需调整参数接收:
[HttpPost("ExportRotativa")] [ValidateAntiForgeryToken] public async Task<IActionResult> ExportRotativa([FromForm] string paramModel) { // 解析JSON字符串为参数模型 var complexParam = System.Text.Json.JsonSerializer.Deserialize<YourComplexParamModel>(paramModel); // 后续逻辑同方案一 }
额外注意事项
- 确保已正确注册Rotativa服务:在
Program.cs中添加builder.Services.AddRotativa(); - 若视图中使用了Session,需确保Session配置正确,且控制器方法允许访问Session
- 测试时注意浏览器弹窗拦截设置,避免新标签页被拦截
内容的提问来源于stack exchange,提问作者Diego
相关产品推荐
相关产品推荐

