views:

195

answers:

4

Similar to this question, we are developing a Web app where the client clicks a button to receive a PDF from the server. Right now we're using the .ajax() method with jQuery to POST the data the backend needs to generate the PDF (we're sending XML) when the button is pressed, and then the backend is generating the PDF entirely in-memory and sending it back as application/pdf in the HTTP response.

One answer to that question requires the server-side save the PDF to disk so it can give back a URL for the client to GET. But I don't want the backend caching content at all.

The other answer suggests the use of a jQuery plugin, but when you look at its code, it's actually generating a form element and then submitting the form. That method will not work for us since we are sending XML data in the body of the HTTP request.

Is there a way to have the browser open up the PDF without caching the PDF server-side, and without requiring us to throw out our send-data-to-the-server-using-XML solution?

(I'd like the browser to behave like it does when a form element is submitted -- a POST is made and then the browser looks at the Content-type header to determine what to do next, like load the PDF in the browser window, a la Safari)

+1  A: 

I see some solutions :

1) submit it to a simple servlet, stream the file through an xslt processor (e.g. saxon) which convert it to xsl-fo (a kind of xml page description language) which can be turned into PDF using FOP or RenderX.

2) submit to a servlet, parse the xml in bean arrays or whatever suitably structured data model which can be handled by a reporting engine, then pass that to a reporting engine (e.g Birt, JasperReports, ...) which support PDF rendering as a standard output format. If the XML is small, you could maybe just pass it completely to the reporting engine servlet and do the processing inside the report itself. I know one of them has a Javascript Data Source which can do the transformations.

3) Use iText to generate PDF from the parsed xml in a servlet, but I never used that before, so I have no idea how that would work.

Peter Tillemans
You misunderstand completely. I am already creating the PDF file. I don't need help with that. I need help serving that PDF file to the user in their browser after they hit the button.
Shaggy Frog
My apologies.I guess your issue is related to the fact that the requesst is being handled by javascript rather than the browser itself. If you change the calling to open in a new window or tab and just let the browser handle it, it should do the right thing provided the right contentType is set (and the right filename extension for good measure) in the response headers.
Peter Tillemans
Opening in a new window requires a location. Which requires a URL. Which means the PDF must be available, cached server-side, for a *second* HTTP request (a GET). As I stated originally, I don't want to cache anything (write to disk) server-side.
Shaggy Frog
It does require a URL for the GET, but that doesn't mean a file has to be written to disk. It just means that the request has to go to the process that can write the PDF output. Cocoon flowscript has continuations that can do this -- your script sends a continuation URL that picks up where the script left off. ( I think there's also a way to do something similar with frameworks like node.js or twisted, but not sure. )
Steven D. Majewski
You're right, the file doesn't need to be written to disk. However, the idea of continuations replaces one problem (disk I/O management) with another (resource possibly shared by multiple threads or processes), because instead of writing the PDF to disk, you have to save some intermediate information that can create that PDF off to the side. And that information needs to be stored in some sort of data structure where multiple producers will be adding to it and multiple consumers will be removing from it.
Shaggy Frog
A: 

Just create the appropriate content headers and write the PDF back in the response. You don't need to cache the PDF you created in the same way you don't need to cache dynamically generated html or images.

Graham Chiu
I am doing this. The problem is that the HTTP response is not being handled by the browser on the client side.
Shaggy Frog
I suggest that you use wireshark to trace the transaction to look at the headers you are generating. This should tell you why it is not working for you.
Graham Chiu
@ShaggyFrog: don't use ajax method on the client. Just do a regular POST. The browser will do it's thing if you let it.
Steven D. Majewski
Please describe what you mean by "just do a regular POST", keeping in mind that I am trying to send XML as part of the HTTP request *body*.
Shaggy Frog
So, what does the http response look like?
Graham Chiu
An application/pdf stream
Shaggy Frog
A: 

I have the same problem: After sending a form via jquery/ajax a generated pdf should open.

Lotta
+1  A: 

Here is a sample form that allows you to input some text, and a PDF appears in the browser. Well, it does for me. And all I do is create the PDF in memory, set the response body to the PDF, and the response header to application/pdf. And that's it.

See http://129.33.194.254:8080/makepdf.rsp for the working example.

If it doesn't work for you, trace the http transaction using wireshark.

<html>
<body>
<%
    either none? text: select request/content 'data [
        %>
        <strong> PDF Test </strong>
        <form method="post">
        Enter some text:
        <input type="text" name="data" value="">
        <input type="submit" value="Submit">
        </form>
        <%
    ][
    if not exists? %pdf-maker.r [
        write %pdf-maker.r read http://www.colellachiara.com/soft/Misc/pdf-maker.r
    ]
    if not value? 'layout-pdf [
        *do %pdf-maker.r
    ]
    response/buffer: layout-pdf compose/deep [[textbox [(dehex text)]]]
    response/set-header 'Content-type "application/pdf"
    ]
%>
</body>
</html>
Graham Chiu
What language is this? I have never seen code like this. I also can't parse if it's sending data via the HTTP Request body (and not as a URL encoded query string), and it looks like it's somehow modifying the response body.
Shaggy Frog
The language, Rebol ( see http://www.rebol.com ) is unimportant. It would work just the same if I used a GET instead of a POST. I don't understand why you say you can parse only by using a GET. And yes, you have to create a response to send back to the client, and in this framework, we just set the response/buffer, and the web server streams it back to the client. I'm pretty sure that's how it is done in Zope and other servers too.If you use Firefox, you can use http headers addon to see what your web server is sending back to you with your own code for crucial debugging.
Graham Chiu
(1) The language is definitely important, since I'm hoping to just use HTML/JS on the client side and Java on the server side (2) I was using "parse" in the sense "I am trying to read this to understand what it does". (3) I can't use a GET instead of a POST, since GET does not allow an arbitrary body of data (for more on that read the HTTP spec) (4) Based on your answer and your comment, I think you misunderstand the question and the requirements involved here
Shaggy Frog
The example I gave you uses a HTTP post ( <form method="post"> ).
Graham Chiu