4

I've a need to generate a PDF with dynamic content intercepted by end user in an editable input form.

So, I tried reading everything on the form into a string and passed the string as a URL parameter that is ready by my PDF generation visualforce page and is getting an error like this now:

ERROR Message:

URL starting with 'https://java-ability-7401-dev-ed--c.visualforce.com/apex/generatepdf?customFormData=%7B%22saveRecor'... is longer than the maximum allowed length of 4,096

Here is a brief excerpt from my code:

PageReference thePage   = Page.generatePDF;
thePage.getParameters().put('Id', recordId);
thePage.getParameters().put('customFormData', customFormData);
thePage.getContent();

I'm getting error at this line thePage.getContent().

Anyway I can generate this PDF file. Please note that this data needs to be accepted from end user via an input form (i.e. this data is not saved in salesforce objects, so I can't fire SOQL and read it from there).

------ EDIT from provided comments & suggestions ------

PageReference thePage   = Page.generatePDF;
thePage.getParameters().put('Id', recordId);
thePage.getParameters().put('tempId', templateId);
thePage.getParameters().put('type', type);
//thePage.getParameters().put('customFormData', customFormData);

Http h              = new Http();
HttpRequest req     = new HttpRequest();
req.setEndpoint(URL.getOrgDomainUrl().toExternalForm() + thePage.getUrl());
req.setMethod('POST');
req.setHeader('Authorization', 'Bearer '+UserInfo.getSessionId());
req.setHeader('Content-Type', 'application/json');
req.setBody('customFormData='+customFormData);

HttpResponse httpRes = h.send(req);
system.debug('httpRes '+ httpRes.getBody());
system.debug('httpRes blob'+ httpRes.getBodyAsBlob());

And this is not throwing me exception like before but now my PDFs are generated as corrupt.

The Debug Output looks correct to me and no errors as such:

16:04:29:175 CALLOUT_REQUEST [99]|System.HttpRequest[Endpoint=https://java-ability-7401-dev-ed.cs41.my.salesforce.com/apex/generatepdf?Id=a0f55000002e7gaAAA&tempId=a0655000003P0HiAAK&type=pdf, Method=POST] 16:04:29:237 CALLOUT_RESPONSE [99]|System.HttpResponse[Status=OK, StatusCode=200]


--------- EDIT 2 ------------ After more debugging it turns out the Visualforce PDF output is executed based on the Endpoint URL of the HttpRequest.

Visualforce Output PDF correctly if 'm using following Endpoint:

req.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm() + thePage.getUrl());

And Visualforce Output PDF is corrupt when endpoint is:

req.setEndpoint(URL.getOrgDomainUrl().toExternalForm() + thePage.getUrl());

But this endpoint change is troubling because if I use getSalesforceBaseUrl() then it has to be provided into Remote Site Settings, and if I use 'getOrgDomainUrl()` then I can use it without Remote Site Setting entry.

Now, this behaviour is coming out differently only for Visualforce URL. If I access basic REST API endpoint with my above code to read a ListView or records, then same Authentication header works fine with getOrgDomainUrl() endpoint.

1 Answer 1

5

There are a few options, but basically you need to get the bulk data out of the query string.

Typically you would do this by using a POST request rather than a GET request. Since a PageReference doesn't give you this option you could do the redirect from the client side directly to the target Visualforce page. That way all the form data can go in the request rather than the URL.

Alternatively, you could do an HttpRequest from the Apex directly to the Visualforce page. The response will still come back from the Http send. It does mean you will need to handle the headers required by Salesforce to authenticate the request.

One final option would be to store the form data in an intermediate sobject before redirecting to the Visualforce page. They target page could then read the data from the sObject rather than from the query string.


PageReference pdf = Page.generatePDF;
thePage.getParameters().put('Id', recordId);

Http http = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint(Url.getOrgDomainUrl().toExternalForm() + pdf.getUrl());
req.setMethod('POST');
req.setHeader('Authorization', 'Bearer '+getAccessToken());

// Rather than including the data in the GET header we put it into a POST request body.
req.setBody('customFormData=' + customFormData);

HTTPResponse res = http.send(req);
Blob pdfContent = res.getBodyAsBlob();
6
  • I like the idea od APEX based HttpRequest as it suits my operation by large but I am unabke to make it happen. Can you guide me a bit on how to pass the Apex properties in my visualforce backend controller in setBody()? It doesn't seem to work my pdf is generated as a curropt file.
    – VarunC
    Dec 2, 2019 at 21:52
  • @VarunC You would need to verify that the controller for the Visualforce page is reading the input parameters from the request rather than via the headers. .getParameters() from the current page should work here. Dec 3, 2019 at 0:41
  • I tried my code formulated on your approach. It does not throw exception as such but I'm unable to generate a PDF that is not corrupt :-(
    – VarunC
    Dec 3, 2019 at 10:43
  • @VarunC Maybe test it independently of Apex. Use an external tool like Postman to send the POST request in with the required headers to conform that the Visualforce page is sending the expected PDF response. Dec 3, 2019 at 18:28
  • I further debugged and found out that if I change my endpoint then PDF is generated with same code, but I don't want to use that end point as it is dependent on setting up Remote Site Setting record. Is your getAccessToken() method in your generates user session a little differently? I always thought I did not had to sue OAuth specific flow to first generate token etc and then use it for execution logic.
    – VarunC
    Dec 3, 2019 at 20:04

You must log in to answer this question.

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