我正在尝试生成一个包含HTML内容的PDF文件,该内容通过JavaScript从AJAX发送。
我正确地发送了HTML,并且使用HTML正确生成了PDF,但我一直试图弄清楚如何在用户的浏览器上启动文件下载。
这就是我目前正在尝试的。这在直接命名文件的URL时在IHttpHandler
文件中有效,但在通过AJAX发布时在ApiController
中不起作用。
我也尝试使用相同的结果发布到IHttpHandler文件。一切正常,直到我尝试使用BinaryWrite
启动下载。
public class DownloadScheduleController : ApiController
{
public void Post(HtmlModel data)
{
var htmlContent = data.html;
var pdfBytes = (new NReco.PdfGenerator.HtmlToPdfConverter()).GeneratePdf(htmlContent);
using (var mstream = new System.IO.MemoryStream())
{
HttpContext.Current.Response.ContentType = "application/pdf";
HttpContext.Current.Response.AppendHeader("content-disposition", "attachment; filename=UserSchedule.pdf");
HttpContext.Current.Response.BinaryWrite(pdfBytes);
HttpContext.Current.Response.End();
}
}
}
这是Ajax请求。它使用的是Angular的$ http。
$http({
method: 'POST',
url: 'api/downloadSchedule',
dataType: "json",
contentType: "application/json; charset=utf-8",
data: data
});
或者我可以将PDF二进制文件返回给JavaScript,但是如何使用JavaScript来保存pdf?
任何帮助将不胜感激。
答案 0 :(得分:2)
出于安全原因,浏览器无法从AJAX请求启动文件下载。它只能通过导航到发送文件的页面来完成。
通常,如果您需要从Javascript发起下载,您可以设置window.location.href = urlToFile
,也可以创建指向该网址的新iframe。
在你的情况下这不会起作用,因为上面的方法只执行一个GET请求,你需要一个POST,所以我只看到两个可能的解决方案:
如果您选择第二个解决方案,您可以遵循在服务器端使用两种方法的方法:
生成文件并将其保存在缓存中的一个POST(可能有更好的解决方案使用缓存,特别是如果您在服务器场上,但让我们保持简单)
一个GET,它检索缓存的内容并将其返回给用户。通过这种方式,您可以通过AJAX调用发布数据,然后通过导航到正确的URL来获取文件。
您的C#代码如下所示:
public class DownloadScheduleController : ApiController
{
public object Post(HtmlModel data)
{
var htmlContent = data.html;
var pdfBytes = (new NReco.PdfGenerator.HtmlToPdfConverter()).GeneratePdf(htmlContent);
var policy = new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(30), Priority = CacheItemPriority.NotRemovable };
var cacheId = Guid.NewGuid().ToString();
MemoryCache.Default.Add("pdfBytes_" + cacheId, pdfBytes, policy);
return new { id = cacheId };
}
public void Get(string id)
{
var pdfBytes = MemoryCache.Default.Get("pdfBytes_" + id);
MemoryCache.Default.Remove("pdfBytes_" + id);
using (var mstream = new System.IO.MemoryStream())
{
HttpContext.Current.Response.ContentType = "application/pdf";
HttpContext.Current.Response.AppendHeader("content-disposition", "attachment; filename=UserSchedule.pdf");
HttpContext.Current.Response.BinaryWrite(pdfBytes);
HttpContext.Current.Response.End();
}
}
}
你的前端可能是这样的:
$http({
method: 'POST',
url: 'api/downloadSchedule',
dataType: "json",
contentType: "application/json; charset=utf-8",
data: data
}).success(function(response) {
// note: the url path might be different depending on your route configuration
window.location.href = 'api/downloadSchedule/' + response.id;
});
请记住,我的代码只是为了向您展示方法,它并不意味着在生产中使用它。例如,您应该在使用后立即清除缓存。在使用之前,您还应该在Get方法中对从缓存中检索到的内容进行完整性检查。此外,根据您的要求,您可能希望对存储和检索的数据采取其他安全预防措施。