Replies: 2 comments
-
|
if these are not in memory created probably standard library sendfile can help this needs to be adjusted to Echo interface w.Header().Set("Content-Disposition", `attachment; filename="report.pdf"`)
http.ServeFile(w, r, "./files/report.pdf") |
Beta Was this translation helpful? Give feedback.
-
|
For on-disk PDFs func servePDF(c echo.Context) error {
path := "./files/report.pdf"
f, err := os.Open(path)
if err != nil {
return echo.NewHTTPError(http.StatusNotFound)
}
defer f.Close()
stat, err := f.Stat()
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError)
}
c.Response().Header().Set("Content-Type", "application/pdf")
c.Response().Header().Set(
"Content-Disposition",
`inline; filename="report.pdf"`, // "attachment" forces download
)
// Let http.ServeContent handle Range, ETag, and Last-Modified correctly.
http.ServeContent(c.Response().Writer, c.Request(), stat.Name(), stat.ModTime(), f)
return nil
}A few important nuances vs.
If the PDF is generated on the flyYour third option ("stream PDF bytes") is the right move — but it's generated-content streaming, not file streaming. Two shapes: A. You can seek while generating (uncommon for PDFs but possible with a tempfile): tmp, _ := os.CreateTemp("", "report-*.pdf")
defer os.Remove(tmp.Name())
defer tmp.Close()
if err := pdfgen.Write(tmp); err != nil { return err }
if _, err := tmp.Seek(0, 0); err != nil { return err }
stat, _ := tmp.Stat()
c.Response().Header().Set("Content-Type", "application/pdf")
c.Response().Header().Set("Content-Disposition", `inline; filename="report.pdf"`)
http.ServeContent(c.Response().Writer, c.Request(), "report.pdf", stat.ModTime(), tmp)
return nilTempfile cleanup is a B. You cannot seek (pure streaming): c.Response().Header().Set("Content-Type", "application/pdf")
c.Response().Header().Set("Transfer-Encoding", "chunked")
c.Response().WriteHeader(http.StatusOK)
// Stream bytes directly into the response. Flush every so often
// so intermediaries don't buffer the whole body.
pr, pw := io.Pipe()
go func() {
defer pw.Close()
if err := pdfgen.Write(pw); err != nil {
pw.CloseWithError(err)
}
}()
_, err := io.Copy(c.Response().Writer, pr)
return errTrade-offs vs A:
What I'd pick
The "file on disk" is the suboptimal middle option only if you're thinking of it as "load bytes into memory" — with |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
AFAIK, there are three ways to serve PDFs:
However, I am not familiar with how to implement PDF streaming using Echo. Any hints on how I could achieve this?
Beta Was this translation helpful? Give feedback.
All reactions