کدهای سمت سرور دریافت فایل PDF
در اینجا کدهای سمت سرور برنامه، نکتهی خاصی را به همراه نداشته و صرفا یک فایل PDF ساده (محتوای باینری) را بازگشت میدهد:
using Microsoft.AspNetCore.Mvc; namespace AngularTemplateDrivenFormsLab.Controllers { [Route("api/[controller]")] public class ReportsController : Controller { [HttpGet("[action]")] public IActionResult GetPdfReport() { return File(virtualPath: "~/assets/sample.pdf", contentType: "application/pdf", fileDownloadName: "sample.pdf"); } } }
سرویس دریافت محتوای باینری در برنامههای Angular
برای اینکه HttpClient برنامههای Angular بتواند محتوای باینری را بجای محتوای JSON پیشفرض آن دریافت کند، نیاز است نوع خروجی سمت سرور آنرا به blob تنظیم کرد:
import { Injectable } from "@angular/core"; import { Observable } from "rxjs/Observable"; import { HttpClient } from "@angular/common/http"; @Injectable() export class DownloadPdfDataService { constructor(private httpClient: HttpClient) { } public getReport(): Observable<Blob> { return this.httpClient.get("/api/Reports/GetPdfReport", { responseType: "blob" }); } }
اصلاح Content Security Policy سمت سرور جهت ارائهی محتوای blob
پس از دریافت فایل PDF به صورت یک blob، با استفاده از متد URL.createObjectURL میتوان آدرس موقت محلی را برای دسترسی به آن تولید کرد و یک چنین آدرسهایی به صورت blob:http تولید میشوند. در این حالت در Content Security Policy سمت سرور، نیاز است امکان دسترسی به تصاویر و همچنین اشیاء از نوع blob را نیز آزاد معرفی کنید:
img-src 'self' data: blob: default-src 'self' blob: object-src 'self' blob:
دریافت فایلهای PDF از سرور و نمایش آنها در یک برنامهی Angular
پس از این مقدمات، کامپوننتی که یک فایل PDF را از سمت سرور دریافت کرده و نمایش میدهد، چنین کدی را خواهد داشت:
import { DownloadPdfDataService } from "./../download-pdf-data.service"; import { WindowRefService } from "./../../core/window.service"; import { Component, OnInit } from "@angular/core"; import { DomSanitizer, SafeResourceUrl } from "@angular/platform-browser"; @Component({ templateUrl: "./view-pdf.component.html", styleUrls: ["./view-pdf.component.css"] }) export class ViewPdfComponent implements OnInit { private nativeWindow: Window; private pdfBlobUrl: string; sanitizedPdfBlobResourceUrl: SafeResourceUrl; constructor(private downloadService: DownloadPdfDataService, private windowRefService: WindowRefService, private sanitizer: DomSanitizer) { } ngOnInit() { this.nativeWindow = this.windowRefService.nativeWindow; this.downloadService.getReport().subscribe(pdfDataBlob => { console.log("pdfDataBlob", pdfDataBlob); const urlCreator = this.nativeWindow.URL; this.pdfBlobUrl = urlCreator.createObjectURL(pdfDataBlob); console.log("pdfBlobUrl", this.pdfBlobUrl); this.sanitizedPdfBlobResourceUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.pdfBlobUrl); }); } }
<h1>Display PDF Files</h1> <div *ngIf="sanitizedPdfBlobResourceUrl"> <h4>using iframe</h4> <iframe width="100%" height="600" [attr.src]="sanitizedPdfBlobResourceUrl" type="application/pdf"></iframe> <h4>using object</h4> <object [attr.data]="sanitizedPdfBlobResourceUrl" type="application/pdf" width="100%" height="100%"></object> <h4>usin embed</h4> <embed [attr.src]="sanitizedPdfBlobResourceUrl" type="application/pdf" width="100%" height="100%"> </div>
- سپس مشترک متد getReport دریافت فایل PDF شده و اطلاعات نهایی آنرا به صورت pdfDataBlob دریافت میکنیم.
- این اطلاعات باینری را به متد createObjectURL ارسال کرده و آدرس موقتی این تصویر را در مرورگر بدست میآوریم.
- چون در این حالت Angular این URL را امن سازی میکند، یک چنین خروجی unsafe:blob بجای blob تولید خواهد شد که نمایش این مورد نیز توسط مرورگر سد میشود. برای رفع این مشکل، میتوان از سرویس DomSanitizer آن که به سازندهی کلاس تزریق شدهاست استفاده کرد:
this.sanitizedPdfBlobResourceUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.pdfBlobUrl);
اینبار یک چنین انتسابی به صورت مستقیم کار میکند که سه نمونهی این انتساب را به اشیاء iframe ،object و embed، در قالب فوق مشاهده میکنید.
افزودن دکمهی چاپ PDF به برنامه
پس از اینکه به this.pdfBlobUrl دسترسی یافتیم، اکنون میتوان یک iframe مخفی را ایجاد کرد، سپس src آنرا به این آدرس ویژه تنظیم نمود و در آخر متد print آنرا فراخوانی کرد که سبب نمایش خودکار دیالوگ چاپ مرورگر میشود:
printPdf() { const iframe = document.createElement("iframe"); iframe.style.display = "none"; iframe.src = this.pdfBlobUrl; document.body.appendChild(iframe); iframe.contentWindow.print(); }
نمایش فایل PDF در یک برگهی جدید
اگر علاقمند بودید تا این فایل PDF را به صورت تمام صفحه و در برگهای جدید نمایش دهید، میتوان از متد window.open استفاده کرد:
showPdf() { this.nativeWindow.open(this.pdfBlobUrl); }
دریافت فایل PDF
بجای نمایش فایل PDF میتوان دکمهای را بر روی صفحه قرار داد که با کلیک بر روی آن، این فایل توسط مرورگر به صورت متداولی جهت دریافت به کاربر ارائه شود:
downloadPdf() { const fileName = "test.pdf"; const anchor = document.createElement("a"); anchor.style.display = "none"; anchor.href = this.pdfBlobUrl; anchor.download = fileName; document.body.appendChild(anchor); anchor.click(); }
این روش در مورد تدارک دکمهی دریافت تمام blobهای دریافتی از سرور کاربرد دارد و منحصر به فایلهای PDF نیست.
کدهای کامل این مطلب را از اینجا میتوانید دریافت کنید.