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)
}
Related
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 have a go project which uses VueJS to provide web interface. While build the project, I first use npm run build to compile the frontend code, which is generated under gui/dist of my project dir. Then I use this code to serve the static contents:
//go:embed gui/dist/*
var dist embed.FS
gui := http.FileServer(http.FS(dist))
http.Handle("/", gui)
http.HandleFunc("/api/", func(w http.ResponseWriter, r *http.Request) {
msg := fmt.Sprintf("TODO: %s", r.URL)
http.Error(w, msg, http.StatusNotImplemented)
})
svr := http.Server{
Addr: fmt.Sprintf(":%v", cf.HTTPPort),
ReadTimeout: time.Minute,
WriteTimeout: time.Minute,
}
assert(svr.ListenAndServe())
The problem is, when open the site in browser, it shows me a browse file interface, i.e. starting with gui, and then into dist, then shows the index.html file, which is a blank page, because it requires files such as /css/..., while the go web server serves it at /gui/dist/css/....
I tried to use http.StripPrefix() but apparently it is not intended to handle this situation, or I didn't use it correctly:
http.Handle("/", http.StripPrefix("/gui/dist", gui))
which generated a 404 page not found.
You may use fs.Sub(dist, "gui/dist") (docs), try it:
package main
import (
"embed"
"fmt"
"io/fs"
"log"
"net/http"
)
func main() {
http.Handle("/", http.FileServer(getFileSystem()))
http.HandleFunc("/api/", api)
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal(err)
}
}
func getFileSystem() http.FileSystem {
fsys, err := fs.Sub(dist, "gui/dist")
if err != nil {
log.Fatal(err)
}
return http.FS(fsys)
}
func api(w http.ResponseWriter, r *http.Request) {
msg := fmt.Sprintf("TODO: %s", r.URL)
http.Error(w, msg, http.StatusNotImplemented)
}
//go:embed gui/dist/*
var dist embed.FS
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
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.
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)
}
}