Golang http写响应而无需等待完成

I'm building an application that builds a pdf file and returns it to the client whenever it receives a request.

Since some of these pdf files might take some time to generate, I would like to periodically send some sort of status update back to client while it is running.

When it's finished building the pdf file, it should be returned to the client as well.

Something akin to:

func buildReport(writer http.ResponseWriter, request *http.Request){
    //build pdf build pdf file
    for { //for example purposes only
        writer.Write([]byte("building. Please wait."))
    }
    pdf.OutputFileAndClose("report.pdf")
    //set header to pdf so that the client knows it's a PDF
    writer.Header().Set("Content-Type", "application/pdf")
    http.ServeFile(writer, request, "report.pdf")
}

func main() {
    http.HandleFunc("/", buildReport)
    http.ListenAndServe(":8081", nil)
}

Setting the header might not work, as the writer can only have one header.

TL;DR is that it cannot be implemented that way. You need to

  1. An API that requests the PDF creation. That queues PDF creation job in a task queue (so that too many PDF creation requests won't blow the HTTP server worker pool)
  2. Provide an API that allows you to check where are you with the PDF rendering (I am assuming that the job can provide interim stats). This is going to be polled by the client on a regular basis.
  3. An API to pull the PDF once it is ready.

Hope this helps and best of luck with your project.

This is by no means comprehensive, but a reasonable example of how you might construct your API (which needs to be asynchronous, as the previous respondent pointed out) can be found here: https://www.adayinthelifeof.nl/2011/06/02/asynchronous-operations-in-rest/

The job queue model is a pretty common one. I would recommend you also write a basic API binding library (you'd want this for your own testing purposes in any case) so that your users can understand how you intend them to use the API, and in writing it, you'll get a better sense of how asynchronous REST interactions feel from the end user side.

Contrary to what others have said, what you want is in fact directly possible but requires fullfillment of the two preconditions:

  • HTTP/1.1 and above.
  • You'll be sending custom content to the clients — not PDF data directly, — and they're prepared to accept and parse it.

You can then employ the so-called "chunked" payload encoding specifically invented to handle "streamed" downloads where the server does not know how many bytes it's about to send.

So you may invent some creative kind of payload where you first periodically stream a "no op" / "progress" marker and then the actual payload. Say, while the file is being prepared you periodically send a line of text reading "PROCESSING" + LF then, when a result is ready you send a line of text "READY" SIZE + LF where SIZE is the size, in bytes, of the immediately following PDF document. After the document is streamed, the server signals the end of data.

Hence the stream would look like

PROCESSING
PROCESSING
…
PROCESSING
READY 8388608
%PDF-1.3
…
%%EOF

The clients have to be able to parse this information from the stream they're receiving and have a simple FSM in place to switch from state to state as they fetch your stream.

The server has to make sure it flushes the stream after each "informational" line otherwise the whole thing would not be "interactive".

If you have a good idea about the overall state of the processing of the document, each "status update" line could include the percentage of the work done, like in "PROCESSINGNN" + LF.