So whenever I try to access any files in my static sub-directory, I just get a 404, Not Found, Accessing Home/ on the other hand works just fine, but a picture that I call from the home file is simply broken :(, So I'd like to know what to change so that I can serve files and redirect my root directory at the same time.
My Path structure:
root/
->html
->static
->entry.go
I saw the other threads on here, they all recommend that I do r.PathPrefix("/").Handler(...), but doing that makes it so accessing any file outside static returns NIL, including my html files which are in a separate html file in the root of my project, furthermore, redirecting to any of them returns 404, Not Found.
Here's the code:
package main
import (
"fmt"
"net/http"
"html/template"
"github.com/gorilla/mux"
"os"
)
func IfError(err error, quit bool) {
if err != nil {
fmt.Println(err.Error())
if(quit) {
os.Exit(1);
}
}
}
func NotFound(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(404)
t, _ := template.ParseFiles("html/404")
err := t.Execute(w, nil)
IfError(err, false)
}
func Home(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("html/home")
err := t.Execute(w, nil)
IfError(err, false)
}
func RedirectRoot(servefile http.Handler) http.Handler {
return http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
redirect := r.URL.Host+"/home"
http.Redirect(w, r, redirect, http.StatusSeeOther)
} else {
servefile.ServeHTTP(w, r)
}
})
}
func main() {
r := mux.NewRouter()
ServeFiles := http.StripPrefix("/", http.FileServer(http.Dir("static/")))
r.Handle("/", RedirectRoot(ServeFiles))
r.HandleFunc("/home", Home)
r.NotFoundHandler = http.HandlerFunc(NotFound)
fmt.Printf("Listening ...")
IfError(http.ListenAndServe(":8081", r), true)
}
Thank you very much
The issue I see in your code
r.Handle("/", RedirectRoot(ServeFiles))
It will match every route, may produce unexpected results. Instead map your routes clearly and explicitly then it will work as you expect.
For eg.: Let's maps the handler with responsibility. This approach based on your directory structure.
It will only expose static directory via file server, remaining files and root directory is safe.
func main() {
r := mux.NewRouter()
r.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
r.HandleFunc("/home", Home)
r.NotFoundHandler = http.HandlerFunc(NotFound)
fmt.Printf("Listening ...")
IfError(http.ListenAndServe(":8081", r), true)
}
RedirectRoot may not be needed for your purpose.
Now, /static/* served by http.FileServer and /home handled by Home.
EDIT:
As asked in the comment. To map root / to home handler and /favicon.ico, add following in-addition to above code snippet.
func favIcon(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "static/favicon.ico")
}
r.HandleFunc("/favicon.ico", favIcon)
r.HandleFunc("/", Home)
favicon.ico served from static directory.
Related
I am working on this API in GO and im using gorilla/mux for my routing. THe home page with path "/" works fine, while routes like "/login" and "/register" return 404
package main
import (
"fmt"
"github.com/gorilla/mux"
"go-api/controller/ad"
"log"
"net/http"
"path"
)
func homePage(w http.ResponseWriter, r *http.Request) {
p := path.Dir("./public/views/index.html")
w.Header().Set("Content-type", "text/html")
http.ServeFile(w, r, p)
}
func showLogin(w http.ResponseWriter, r *http.Request) {
p := path.Dir("./public/views/login.html")
w.Header().Set("Content-type", "text/html")
http.ServeFile(w, r, p)
}
func showRegister(w http.ResponseWriter, r *http.Request) {
p := path.Dir("./public/views/register.html")
w.Header().Set("Content-type", "text/html")
http.ServeFile(w, r, p)
}
func main() {
baseUrl := "localhost:9010"
r := mux.NewRouter()
r.HandleFunc("/", homePage).Methods("GET")
r.HandleFunc("/ads", Ad.GetAds).Methods("GET")
r.HandleFunc("/login", showLogin).Methods("GET")
r.HandleFunc("/register", showRegister).Methods("GET")
http.Handle("/", r)
fmt.Printf("Server running at: %s", baseUrl)
log.Fatal(http.ListenAndServe(baseUrl, nil))
}
Yes, all 3 files exist in folder public/views:
index.html
login.html
register.html
What am I doing wrong? -How do I fix it so that the pages will show normally?
The cause is in the places where a directory is determined instead of the actual files to be used, e.g.
p := path.Dir("./public/views/login.html")
Go's documentation of Dir states:
Dir returns all but the last element of path, typically the path's directory.
But since you want to deliver the actual file, you should use the file path. The handler function would then look something like this:
func showLogin(w http.ResponseWriter, r *http.Request) {
p := "./public/views/login.html"
w.Header().Set("Content-type", "text/html")
http.ServeFile(w, r, p)
}
Note the removed path.Dir.
http://localhost:9010/login now serves the login.html file as expected.
(Generally, for testing, it is always good to clear the browsing data before testing so that no cached data is displayed.)
I am doing a GO course, and whenever I run my server code, I don't get any errors but when I try to type in "localhost:8080" in the browser, I get a message saying "localhost didn’t send any data. ERR_EMPTY_RESPONS". I have the same exact code as the course, except I am using HTML and not TMPL. Why isn't my HTML displaying in the browser?
package main
import (
"fmt"
"html/template"
"net/http"
)
const portNumber = ":8080"
func Home(w http.ResponseWriter, r *http.Request) {
renderTemplate(w, "home.html")
}
func About(w http.ResponseWriter, r *http.Request) {
}
func renderTemplate(w http.ResponseWriter, html string) {
parsedTemplate, _ := template.ParseFiles("./templates" + html)
err := parsedTemplate.Execute(w, nil)
if err != nil {
fmt.Println("error parsing template:", err)
return
}
}
func main() {
http.HandleFunc("/", Home)
http.HandleFunc("/about", About)
fmt.Println(fmt.Sprintf("Starting App on port %s", portNumber))
_ = http.ListenAndServe(portNumber, nil)
}
The ParseFiles method takes a path. You're missing the / after "./templates". So it should be:
parsedTemplate, _ := template.ParseFiles("./templates/" + html)
I'm working on a website using Go. The server constraints require that I use CGI. When I test the following code locally using http.ListenAndServe() (commented out below), the various handlers are called correctly depending on the address requested. However, if I use cgi.Serve() instead, the default router is executed for all addresses (i.e., the handler for "/" is always executed). I'd appreciate any clues as to how to fix the issue.
EDIT: Here is the simplest test case I can think of to show the problem:
//=============SIMPLIFIED CODE================//
package main
import (
"fmt"
"net/http"
"net/http/cgi"
)
func defaultHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Default")
}
func otherHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Other")
}
func main() {
http.HandleFunc("/other", otherHandler)
http.HandleFunc("/", defaultHandler)
/*
//Works fine
err := http.ListenAndServe(":8090", nil)
if err != nil {
panic(err)
}
*/
//Always fires defaultHandler no matter the address requested
err := cgi.Serve(nil)
if err != nil {
panic(err)
}
}
//=============CODE FROM ORIGINAL POST===================//
package main
import (
"fmt"
"net/http"
"net/http/cgi"
"net/url"
"os"
"github.com/go-cas/cas"
)
func logoutHandler(w http.ResponseWriter, r *http.Request) {
cas.RedirectToLogout(w, r)
}
func calendarHandler(w http.ResponseWriter, r *http.Request) {
if !cas.IsAuthenticated(r) {
cas.RedirectToLogin(w, r)
}
fmt.Fprintf(w, "Calendar for %s", cas.Username(r))
}
func defaultHandler(w http.ResponseWriter, r *http.Request) {
if !cas.IsAuthenticated(r) {
cas.RedirectToLogin(w, r)
}
fmt.Fprintf(w, "Hi there %s!", cas.Username(r))
}
func main() {
u, _ := url.Parse("https://www.examplecasserver.com")
client := cas.NewClient(&cas.Options{
URL: u,
})
http.Handle("/logout", client.HandleFunc(logoutHandler))
http.Handle("/calendar", client.HandleFunc(calendarHandler))
http.Handle("/", client.HandleFunc(defaultHandler))
/*
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
*/
err := cgi.Serve(nil)
if err != nil {
panic(err)
}
}
The CGI program expects some variables to be set in order to build the request.
Probably there is some issue with the configuration of your web server in which the variables are either not set correctly or not named correctly.
To verify this:
1) Add this before calling cgi.Serve and you'll see how the right handler is called (otherHandler)
os.Setenv("REQUEST_METHOD", "get")
os.Setenv("SERVER_PROTOCOL", "HTTP/1.1")
os.Setenv("SCRIPT_NAME", "/other")
2) Add this at the beginning of the main to check how the variables are being set by the web server:
fmt.Println(os.Environ())
In that output, look for the CGI meta variables defined in the spec:
http://www.ietf.org/rfc/rfc3875
Look for the section "Request Meta-Variables" in that page, you are probably looking for the SCRIPT_NAME or PATH_INFO variables.
EDIT
From the variable values you pasted below, it seems the issue is that the REQUEST_URI contains an additional path component:
REQUEST_URI=/main.cgi/other
So the easiest fix would be for you to map the routes accordingly:
http.HandleFunc("/main.cgi/other", otherHandler)
http.HandleFunc("/", defaultHandler) // or maybe /main.cgi
Any mistakes in below code? Multiple directory serving is not working from the below code. When I access the localhost:9090/ide, the server will return 404 error.
package main
import (
"log"
"net/http"
)
func serveIDE(w http.ResponseWriter, r *http.Request) {
http.FileServer(http.Dir("/home/user/ide")).ServeHTTP(w, r)
}
func serveConsole(w http.ResponseWriter, r *http.Request) {
http.FileServer(http.Dir("/home/user/console")).ServeHTTP(w, r)
}
func main() {
http.HandleFunc("/ide", serveIDE)
http.HandleFunc("/console", serveConsole)
err := http.ListenAndServe(":9090", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
When I change the code like this,
http.HandleFunc("/", serveIDE)
It will work as I expected.
One of the issues with using http.FileServer is that the request path is used to build the file name, so if you're serving from anywhere but the root you need to strip the route prefix to that handler.
The standard library includes a helpful tool for that http.StripPrefix, but that only works on http.Handlers, not http.HandleFuncs, so to use it you need to adapt your HandleFunc to a Handler.
Here is a working version that should do what you want. Note that wHandler is just an adapter from your HttpFunc methods to Hander interface:
package main
import (
"log"
"net/http"
)
func serveIDE(w http.ResponseWriter, r *http.Request) {
http.FileServer(http.Dir("/home/user/ide")).ServeHTTP(w, r)
}
func serveConsole(w http.ResponseWriter, r *http.Request) {
http.FileServer(http.Dir("/home/user/console")).ServeHTTP(w, r)
}
type wHandler struct {
fn http.HandlerFunc
}
func (h *wHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
log.Printf("Handle request: %s %s", r.Method, r.RequestURI)
defer log.Printf("Done with request: %s %s", r.Method, r.RequestURI)
h.fn(w, r)
}
func main() {
http.Handle("/ide", http.StripPrefix("/ide", &wHandler{fn: serveIDE}))
http.Handle("/console", http.StripPrefix("/console", &wHandler{fn: serveConsole}))
err := http.ListenAndServe(":9090", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
I am new to GoLang dev and am trying to make a simple web-app. I have been following this tutorial https://www.youtube.com/watch?v=AiRhWG-2nGU.
However I can not even serve the index.html file.
This is my code
func check(e error) {
if e != nil {
fmt.Println(e)
panic(e)
}
}
func Index(w http.ResponseWriter, r *http.Request) {
fmt.Println("Index functoin")
indexHTML, err := ioutil.ReadFile("index.html")
check(err)
fmt.Println(indexHTML)
w.Write(indexHTML)
}
and this is the error produced
Index functoin
open index.html: no such file or directory
My tree structure is like so
BasicWebServer/
BasicWebServer/main.go
BasicWebServer/index.html
BasicWebServer/static/
BasicWebServer/static/index.html
All I want is to be able to serve the index.html since it is a AngularJS app which is already running smoothly. I tried with static files like so
router := NewRouter()
s := http.StripPrefix("/static/", http.FileServer(http.Dir("./static/")))
but it did not work so I am now trying the most basic approach I could think of.
Please help.
Thank you
If you want BasicWebServer/main.go to show BasicWebServer/index.html, not the one inside the static folder, then it seems you didn't properly configure the HTTP server.
Here's your code, with package declaration, imports and a main function working as you expected.
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func check(e error) {
if e != nil {
fmt.Println(e)
panic(e)
}
}
func Index(w http.ResponseWriter, r *http.Request) {
fmt.Println("Index functoin")
indexHTML, err := ioutil.ReadFile("index.html")
check(err)
fmt.Println(indexHTML)
w.Write(indexHTML)
}
func main() {
http.HandleFunc("/", Index)
err := http.ListenAndServe(":8080", nil)
check(err)
}