Sling Academy
Home/Golang/Streaming Large Files with Go HTTP

Streaming Large Files with Go HTTP

Last updated: November 27, 2024

When you need to build a web server in Go that can efficiently stream large files, understanding how to work with HTTP connections and how to handle file I/O effectively is crucial. Go's net/http package provides features that simplify the task of building web servers, including the ability to handle large file streaming cleanly.

Setting Up a Basic HTTP Server

Before diving into file streaming, let's start by setting up a basic HTTP server with Go. First, create a new Go file (for example, server.go) and write the following code:

package main

import (
    "fmt"
    "net/http"
)

func helloHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello, world!")
}

func main() {
    http.HandleFunc("/hello", helloHandler)
    fmt.Println("Starting server at port 8080")
    if err := http.ListenAndServe(":8080", nil); err != nil {
        panic(err)
    }
}

Running this setup with go run server.go will start a simple web server listening on port 8080. Now, let's proceed to handling large file downloads.

Handling Large File Downloads

Handling large files in Go requires streaming rather than loading the entire file into memory. This approach is efficient and reduces the risk of memory exhaustion, which is critical in server environments. Here is how you can accomplish this.

Step 1: Creating a File Server

To create a file server that can stream files, start by updating the handler function:

import (
    "log"
    "os"
    "path/filepath"
    "strconv"
)

func fileDownloadHandler(w http.ResponseWriter, r *http.Request) {
    filePath := r.URL.Path[len("/download/"):] // Assumes file path is after /download/
    _, fileName := filepath.Split(filePath)
    file, err := os.Open(filePath)
    if err != nil {
        http.Error(w, "File not found.", 404)
        return
    }
    defer file.Close()

    fileStat, err := file.Stat()
    if err != nil {
        http.Error(w, "Internal server error.", 500)
        return
    }

    // Set headers
    w.Header().Set("Content-Disposition", "attachment; filename="+fileName)
    w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
    w.Header().Set("Content-Length", strconv.FormatInt(fileStat.Size(), 10))

    // Stream the file
    http.ServeContent(w, r, fileName, fileStat.ModTime(), file)
}

This handler reads the file from disk in chunks, directly streaming it to the client's browser, therefore saving memory and providing better performance for large files.

Step 2: Update Server with New Handler

Add this new route to your HTTP server configuration:

func main() {
    http.HandleFunc("/download/", fileDownloadHandler)
    fmt.Println("Starting server on :8080")
    if err := http.ListenAndServe(":8080", nil); err != nil {
        log.Fatal(err)
    }
}

This modification tells your server to handle requests directed to the /download/ path with the file download handler, ensuring proper file streaming.

Testing the File Streaming

To test your setup, place any large file within your server's directory. Use a browser or a tool like curl or wget to send a request to http://localhost:8080/download/yourfile.txt.

For example, use the command:

curl -O http://localhost:8080/download/testfile.pdf

This command will successfully download the testfile.pdf if everything is set up correctly.

Conclusion

Streamlining large files with Go’s net/http package is both efficient and straightforward. By streaming files directly from disk, you leverage Go's strengths, including great I/O performance and powerful built-in libraries, to handle large file downloads with ease.

Next Article: Creating a Chat Server with WebSockets in Go

Previous Article: Using Multipart Requests for File Uploads in Go

Series: Networking and Server

Golang

Related Articles

You May Also Like

  • How to remove HTML tags in a string in Go
  • How to remove special characters in a string in Go
  • How to remove consecutive whitespace in a string in Go
  • How to count words and characters in a string in Go
  • Relative imports in Go: Tutorial & Examples
  • How to run Python code with Go
  • How to generate slug from title in Go
  • How to create an XML sitemap in Go
  • How to redirect in Go (301, 302, etc)
  • Using Go with MongoDB: CRUD example
  • Auto deploy Go apps with CI/ CD and GitHub Actions
  • Fixing Go error: method redeclared with different receiver type
  • Fixing Go error: copy argument must have slice type
  • Fixing Go error: attempted to use nil slice
  • Fixing Go error: assignment to constant variable
  • Fixing Go error: cannot compare X (type Y) with Z (type W)
  • Fixing Go error: method has pointer receiver, not called with pointer
  • Fixing Go error: assignment mismatch: X variables but Y values
  • Fixing Go error: array index must be non-negative integer constant