2

I'm creating a PDF viewer using Visualforce and the PDF.js library. My project doesn't include react.

When I try to execute pdfjsLib.getDocument() passing the URL of a PDF stored in Salesforce itself, as an attachment (ContentDocument), I'm getting the following CORS error:

"Access to fetch at [...] redirected from [...] has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled."

Cors Full Error Screenshot

I have done the following when calling getDocument() and it still doesn't work:

  1. I specify the Access-Control-Allow-Origin as '*'
  2. I give a bearer authorization token
  3. I set "withCredentials: true"
  4. I have whitelisted all domains inside CORS configuration in Salesforce Setup

This is my call to the function getDocument():

document.getElementsByClassName("pdfFileSelector")[0].addEventListener('change', (event) => {
            let fileId = event.target.value;
            let currentUrl = window.location.href;
            let domain = currentUrl.substring(0, currentUrl.indexOf('/', 8));
            let fileUrl = domain + '/sfc/servlet.shepherd/document/download/' + fileId + '?origin=' + window.location.host;

            console.log('>>> Url completo');
            console.log(fileUrl);

            pdfjsLib.getDocument({
                url: fileUrl,
                withCredentials: true,
                httpHeaders: {
                    'Access-Control-Allow-Origin': '*',
                    'Access-Control-Allow-Methods': 'GET',
                    'Authorization': 'Bearer {!$Api.Session_ID}'
                },
            }).then((pdf) => {
                myState.pdf = pdf;
                render();
                console.log('>>> Terminó de renderizar. funcionó?');
            });
        });

And these are all the domains that I'm whitelisting from Saelsforce > Setup > CORS:

All domains whitelisted in CORS configuration

None of these things have worked. Please help, any suggestion is greatly appreciated, since I've been dealing with this error for 3 days now, looking into any documentation and tutorial/question/forum available, still I'm stuck. Thank you

Here's my full Visualforce Code:

<apex:page controller="CSCACustomPDFPreviewController" lightningStylesheets="true" applyHtmlTag="false" showHeader="false" standardStylesheets="false" sidebar="false" docType="html-5.0">
<head>
    <apex:slds/>
    <apex:includeScript value="{!$Resource.PDFjsLibrary}"/>
    <style>
        .main-container {
            border: 1px solid #C9C9C9;
            border-radius: 2px;
        }
        
        .header-container {
            display: flex;
            align-items: center;
            column-gap: 10px;
            height: 50px;
            background-color: #F3F3F3;
            padding-left: 15px;
        }
        
        .body-container {
            background-color: white;
            padding: 15px;
            border-top: 1px solid #C9C9C9;
        }
        
        .title-text {
            font-size: 14px !important;
        }

        #canvas_container {
            width: 100%;
            height: 800px;
            overflow: auto;
            background: #333;
            text-align: center;
            border: solid 3px;
        }

        .pdfFileSelector {
            width: 100%;
        }
    </style>
</head>

<body class="slds-scope">
    <!-- Header and title of the card-->
    <div class="header-container">
        <span class="slds-icon_container slds-icon-standard-account" >
            <svg aria-hidden="true" class="slds-icon slds-icon--small">
                <use xmlns:xlink="http://www.w3.org/2000/xlink" xlink:href="/apexpages/slds/latest/assets/icons/doctype-sprite/svg/symbols.svg#pdf">
                </use>
            </svg>
        </span>
        <div class="slds-text-heading_small title-text"><b>Custom PDF Preview</b></div>
    </div>
    <!-- // Header and title of the card-->

    <div class="body-container slds-is-relative slds-border_top">
        <br/>
        <!-- PDF file selector-->
        <apex:form >
            <label>Select a file name to display the preview</label>
            <apex:selectList styleclass="pdfFileSelector" size="1">
                <apex:selectOptions value="{!fileOptions}" />       
            </apex:selectList>
        </apex:form>

        <div>
            <p>El resultado de llamad Resource.PDFjsLibrary</p>
            {!$Resource.PDFjsLibrary}
        </div>

        <!--// PDF file selector-->
        <br/>
        <!-- Canvas to render PDF-->
        <div id="my_pdf_viewer">
            <div id="canvas_container">
                <canvas id="pdf_renderer"></canvas>
            </div>
            <br/>
            <div id="navigation_controls">
                <button id="go_previous">Previous</button>
                <input id="current_page" value="1" type="number"/>
                <button id="go_next">Next</button>
            </div>
            <div id="zoom_controls">  
                <button id="zoom_in">+</button>
                <button id="zoom_out">-</button>
            </div>
        </div>
        <!--// Canvas to render PDF-->
    </div>
    
    <script>
        pdfjsLib.GlobalWorkerOptions.workerSrc = '//airliquidehhc-amer--uat.sandbox.lightning.force.com{!$Resource.PDFjsWorker}';

        var myState = {
            pdf: null,
            currentPage: 1,
            zoom: 1
        }
     
        function render() {
            myState.pdf.getPage(myState.currentPage).then((page) => {
                var canvas = document.getElementById("pdf_renderer");
                var ctx = canvas.getContext('2d');
     
                var viewport = page.getViewport(myState.zoom);
                canvas.width = viewport.width;
                canvas.height = viewport.height;
         
                page.render({
                    canvasContext: ctx,
                    viewport: viewport
                });
            });
        }

        document.getElementsByClassName("pdfFileSelector")[0].addEventListener('change', (event) => {
            let fileId = event.target.value;
            let currentUrl = window.location.href;
            let domain = currentUrl.substring(0, currentUrl.indexOf('/', 8));
            let fileUrl = domain + '/sfc/servlet.shepherd/document/download/' + fileId + '?origin=' + window.location.host;

            console.log('>>> Url completo');
            console.log(fileUrl);

            pdfjsLib.getDocument({
                url: fileUrl,
                withCredentials: true,
                httpHeaders: {
                    'Access-Control-Allow-Origin': '*',
                    'Access-Control-Allow-Methods': 'GET',
                    'Authorization': 'Bearer {!$Api.Session_ID}'
                },
            }).then((pdf) => {
                myState.pdf = pdf;
                render();
                console.log('>>> Terminó de renderizar. funcionó?');
            });
        });

        document.getElementById('go_previous').addEventListener('click', (e) => {
            if(myState.pdf == null || myState.currentPage == 1) 
              return;
            myState.currentPage -= 1;
            document.getElementById("current_page").value = myState.currentPage;
            render();
        });

        document.getElementById('go_next').addEventListener('click', (e) => {
            if(myState.pdf == null || myState.currentPage > myState.pdf._pdfInfo.numPages) 
               return;
            myState.currentPage += 1;
            document.getElementById("current_page").value = myState.currentPage;
            render();
        });

        document.getElementById('current_page').addEventListener('keypress', (e) => {
            if(myState.pdf == null) return;
         
            // Get key code 
            var code = (e.keyCode ? e.keyCode : e.which);
         
            // If key code matches that of the Enter key 
            if(code == 13) {
                var desiredPage = 
                document.getElementById('current_page').valueAsNumber;
                                 
                if(desiredPage >= 1 && desiredPage <= myState.pdf._pdfInfo.numPages) {
                    myState.currentPage = desiredPage;
                    document.getElementById("current_page").value = desiredPage;
                    render();
                }
            }
        });

        document.getElementById('zoom_in').addEventListener('click', (e) => {
            if(myState.pdf == null) return;
            myState.zoom += 0.5;
            render();
        });

        document.getElementById('zoom_out').addEventListener('click', (e) => {
            if(myState.pdf == null) return;
            myState.zoom -= 0.5;
            render();
        });
    </script>
</body>

</apex:page>

1 Answer 1

1

I faced the same issue, so the workaround is to get the base64 blob value of the document from ContentVersion and call pdfjsLib.getDocument(). Check this https://mozilla.github.io/pdf.js/examples/

2
  • Hi Rahul, thank you for your answer. Could yo add here the code maybe to have guidance? I also tried that but it didn't work for me. Maybe I did it wrong. Thank you!
    – Emmanuel_M
    Jun 29, 2023 at 15:13
  • I followed the tutorial using atob(base64) but I couldn't make it work
    – Emmanuel_M
    Jun 29, 2023 at 15:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .