0

I'm fairly certain that I've overlooked something obvious, but I'm not sure what. I'm building a simple web application that serves up templated pages of books. The template works fine, and the path for the image seems to be populating correctly, but I keep getting a 404 error for the image itself.

Here is the template:

<h1>{{.Title}}</h1>
<h2>{{.Author.Name}}</h2>
<image src="../images/{{.ImageURI}}" />

and here is the application itself:

package main
import (
    "html/template"
    "log"
    "net/http"
    "time"

    "github.com/gorilla/mux"
    "github.com/user/marketplace/typelibrary"
)

var books []typelibrary.Book

func ItemHandler(w http.ResponseWriter, r *http.Request) {
    params := mux.Vars(r)
    var selected typelibrary.Book       
    //Retrieve item data
    for _, item := range books {
        if item.ID == params["id"] {
            selected = item
            break
        }
    }
    t, _ := template.ParseFiles("./templates/book.html")
    t.Execute(w, selected)
}

func main() {
    router := mux.NewRouter()
    books = append(books, typelibrary.Book{ID: "1", Title: "The Fellowship of the Ring", ImageURI: "LotR-FotR.jpg", Author: &typelibrary.Author{Name: "JRR Tolkien"}})
    books = append(books, typelibrary.Book{ID: "2", Title: "The Two Towers", ImageURI: "LotR-tTT.jpg", Author: &typelibrary.Author{Name: "JRR Tolkien"}})
    books = append(books, typelibrary.Book{ID: "3", Title: "The Return of the King", ImageURI: "LotR-RotK.jpg", Author: &typelibrary.Author{Name: "JRR Tolkien"}})
    books = append(books, typelibrary.Book{ID: "4", Title: "Monster Hunter International", ImageURI: "MHI1.jpg", Author: &typelibrary.Author{Name: "Larry Correia"}})

    router.Handle("/", http.FileServer(http.Dir(".")))
    router.Handle("/images/", http.FileServer(http.Dir("../images/")))
    router.HandleFunc("/item/{id}", ItemHandler).Methods("GET")

    srv := &http.Server{
        Handler:      router,
        Addr:         ":8080",
        WriteTimeout: 10 * time.Second,
        ReadTimeout:  10 * time.Second,
    }
    log.Fatal(srv.ListenAndServe())
}

The images are stored in the images subdirectory, directly below the directory where the executable is. When I attempt to view the broken image in the page, the path shows up as localhost:8080/images/[imagename] but gives a 404 error. What configuration or routing options am I missing here?

  • You are almost certainly passing the wrong path to `http.Dir`. Why `../`? Are you executing the server from a subdirectory? I'd expect you'd want `./images/` based on your description. – Jonathan Hall May 11 '17 at 08:31
  • @Flimzy You are correct, it should properly be `./images/`, however the problem persists either way. – FreeRangeOyster May 11 '17 at 09:00
  • 2
    We don't know your directory structure and how you start your server, but these answers contain the solution: [404 page not found - Go rendering css file](http://stackoverflow.com/questions/28293452/404-page-not-found-go-rendering-css-file/28294524#28294524); and [Why do I need to use http.StripPrefix to access my static files?](http://stackoverflow.com/questions/27945310/why-do-i-need-to-use-http-stripprefix-to-access-my-static-files/27946132#27946132) – icza May 11 '17 at 09:11
  • It's really going to depend on where the images are relative to _the working directory when you execute the binary_. Another approach would be to use a configuration value (from a config file, env var, or CLI flag) to pass in the root path where your content files can be found, and use that rather than relative paths. – Adrian May 11 '17 at 14:25
  • To know. What is `github.com/user/marketplace/typelibrary`? – LeMoussel May 11 '17 at 16:24

1 Answers1

8

You are creating your route incorrectly to serve your images. The Router.Handle() method matches URLs with the Path() matcher, which matches the entire path, while you actually want to match any path that starts with "/image/". Instead, create the route with the PathPrefix() matcher:

var imgServer = http.FileServer(http.Dir("./images/"))
router.PathPrefix("/images/").Handler(http.StripPrefix("/images/", imgServer))

See https://godoc.org/github.com/gorilla/mux#Router.Handle for more information.