http.FileServer only serves index.html - http

My code for a simple file server:
package main
import (
"net/http"
"os"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
// default file handler
r.Handle("/", http.FileServer(http.Dir("web")))
// run on port 8080
if err := http.ListenAndServe(":8080", handlers.LoggingHandler(os.Stdout, r)); err != nil {
panic(err)
}
}
My directory structure is:
cmd/server/main.go
web/index.html
web/favicon.ico
web/favicon.png
web/css/main.css
index.html asks for main.css. so when I run go run cmd/server/main.go I get the following output:
127.0.0.1 - - [24/Dec/2019:22:45:26 -0X00] "GET / HTTP/1.1" 304 0
127.0.0.1 - - [24/Dec/2019:22:45:26 -0X00] "GET /css/main.css HTTP/1.1" 404 19
I'm able to see the index.html page, but without the CSS. When I request any other file (e.g. favicon.ico) I also get a 404. Why does my FileServer only serve index.html?

To demonstrate why this does not work consider the following test app:
package main
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
)
type testHandler struct{}
func (h *testHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Printf("Got request for %s\n", r.URL)
}
func main() {
r := mux.NewRouter()
hndlr := testHandler{}
r.Handle("/", &hndlr)
// run on port 8080
if err := http.ListenAndServe(":8080", r); err != nil {
panic(err)
}
}
If you run this and access http://127.0.0.1:8080/ in your browser it will log Got request for /. However if you access http://127.0.0.1:8080/foo you will get a 404 error and nothing will be logged. This is because r.Handle("/", &hndlr) will only match on / and not anything below it.
If you change this to r.PathPrefix("/").Handler(&hndlr) then it will work as you expect (the router will pass all paths to the handler). So to fix your example change r.Handle("/", http.FileServer(http.Dir("web"))) to r.PathPrefix("/").Handler( http.FileServer(http.Dir("web"))).
Note: Because this is passing all paths to FileServer there is really no need to use Gorilla Mux; I have left this in on the assumption that you will be using it to add some other routes.

Related

Stylesheet not loaded because of MIME-type in go [duplicate]

I'm having issues with including css files in a GO webserver using Gorilla Mux. I get the following error in the Google Chrome console:
forum:1 Refused to apply style from 'http://localhost:8080/css/forum.css' because its MIME type ('text/plain') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
I understand that a lot of people fail using a FileServer by handling the "/" wrong, but this also won't work for me. My file struture is as follow:
file structure
When I run the server, I execute in cmd: go run src/main.go. I also tried running it in the src folder. But that won't work too. In the HTML file, I add the css file with
<link rel="stylesheet" type="text/css" href="/css/forum.css" />
My GO code is below. I tried handling the FileServer in two ways, one of them is commented out above the other. Both won't work. Everything else is working except the FileServer.
package main
import (
"fmt"
"net/http"
"html/template"
"github.com/gorilla/mux"
)
var templates *template.Template
func main() {
r := mux.NewRouter()
templates = template.Must(template.ParseGlob("src/templates/*.html"))
cssHandler := http.FileServer(http.Dir("./static/css"))
r.HandleFunc("/home", homeGetHandler).Methods("GET")
r.HandleFunc("/home", homePostHandler).Methods("POST")
r.HandleFunc("/forum", forumGetHandler).Methods("GET")
r.HandleFunc("/forum", forumPostHandler).Methods("POST")
http.Handle("/forum", r)
http.Handle("/home", r)
// http.Handle("/css/", http.StripPrefix("/src/static/css/", cssHandler))
r.PathPrefix("/css/").Handler(http.StripPrefix("/src/static/css/", cssHandler))
http.ListenAndServe(":8080", nil)
}
func homeGetHandler(w http.ResponseWriter, r *http.Request) {
templates.ExecuteTemplate(w, "home.html", nil)
}
func homePostHandler(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
comment := r.PostForm.Get("comment")
fmt.Println(comment)
http.Redirect(w, r,"/home", 302)
}
func forumGetHandler(w http.ResponseWriter, r *http.Request) {
templates.ExecuteTemplate(w, "forum.html", nil)
}
func forumPostHandler(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
comment := r.PostForm.Get("post")
fmt.Println(comment)
http.Redirect(w, r,"/forum", 302)
}
[SOLUTION]
I found the answer:
http.Handle("/forum", r)
http.Handle("/home", r)
should just be:
http.Handle("/",r)
What's because you're serving your css file with wrong MIME type, you should set right header for css. Use:
func serveCss(w http.ResponseWriter, r *http.Request) {
// some code here
w.Header().Add("Content-Type", "text/css")
// some code here
}
The problem is that your csshandler returns the contents of the file with Content-Type set to "text/plain". You have to set it to "text/css" to have the browser interpret it as a CSS file. You can set the content type before returning the file contents using a middleware-like function:
func SetHeader(header,value string, handle http.Handler) func(http.ResponseWriter,*http.Request) {
return func(w http.ResponseWriter,req *http.Request) {
w.Header().Set(header,value)
handle.ServeHTTP(w,req)
}
}
r.PathPrefix("/css/").HandlerFunc(SetHeader("Content-Type","text/css",http.StripPrefix("/src/static/css/", cssHandler)))

Set base path for follow-up HTTP request

Suppose there is a file called foo.html and a project structure that looks like this:
|--styles
| |--style.css 📜
|--pages
| |--foo.html 📜
foo.html contains (among other stuff):
<link rel="stylesheet" type="text/css" href="styles/style.css">
Now, when the client requests for pages/foo.html, it will see the link to the css file and it will make a follow-up request to pages/styles/style.css. Is there a way I can instead tell it from the file server to make a request to styles/style.css rather than pages/styles/style.css?
I'm using the Go http library from the standard library.
I guess you are already using http go package. Here is the below sample code which can help you to achieve what you intend to do:
package main
import (
"fmt"
"log"
"net/http"
)
func hello(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "hello1\n")
}
func main() {
fs := http.FileServer(http.Dir("./page/static"))
http.Handle("/page/styles/", http.StripPrefix("/page/styles/", fs))
page_fs := http.FileServer(http.Dir("./page"))
http.Handle("/page/", http.StripPrefix("/page/", page_fs))
http.HandleFunc("/hello", hello)
log.Println("Listening on :3000...")
err := http.ListenAndServe(":3000", nil)
if err != nil {
log.Fatal(err)
}
}
Let me know if you need explanation.

Configuring http:localhost for Golang [duplicate]

This question already has answers here:
Run go web application on IIS
(2 answers)
Closed 4 years ago.
I would like to realize some tutorials in Golang which covers net/http library and other web and routing libraries as well. Besides, I use my localhost to test my asp.net core with IIS. I have already stopped my IIS client on my machine and it still redirects me to IIS themed localhost instead of showing my golang Fprintf message.The page on my localhost, my current iis settings, and the golang code can be seen below. Any help would be appreciated.
The page on http:localhost
My IIS situation summary(It is stopped manually)
package main
import "fmt"
import "net/http"
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
numOfBytesWritten, err := fmt.Fprintf(w, "Hello, World!")
if err != nil {
fmt.Fprintln(w, "Error occured!")
}
fmt.Fprintln(w, numOfBytesWritten, " bytes written.")
http.ListenAndServe(":80", nil)
})
}
My sites on ISS.
My mistake was silly :)
http.ListenAndServe(":80", nil)
line should not be inside http.HandleFunc(). So my final code is below and it works as expected.
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
n, err := fmt.Fprintf(w, "Hello World!\n")
if err == nil {
fmt.Fprintf(w, "%d bytes written\n", n)
} else {
fmt.Fprintf(w, "Error occured.")
}
})
http.ListenAndServe(":80", nil)
}
Make sure Default Web Site is not running, looks like you stopped something else.
See the attached image. https://i.stack.imgur.com/OMhjP.png

Unexpected EOF using Go http client

I am learning Go and came across this problem.
I am just downloading web page content using HTTP client:
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
)
func main() {
client := &http.Client{}
req, err := http.NewRequest("GET", "https://mail.ru/", nil)
req.Close = true
response, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer response.Body.Close()
content, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(content)[:100])
}
I get an unexpected EOF error when reading response body. At the same time content variable has full page content.
This error appear only when I downloading https://mail.ru/ content. With other URLs everything works fine - without any errors.
I used curl for downloading this page content - everything works as expected.
I am confused a bit - what's happening here?
Go v1.2, tried on Ubuntu and MacOS X
It looks like the that server (Apache 1.3, wow!) is serving up a truncated gzip response. If you explicitly request the identity encoding (preventing the Go transport from adding gzip itself), you won't get the ErrUnexpectedEOF:
req.Header.Add("Accept-Encoding", "identity")

Go - accepting http post multipart file(s)

I am trying to figure out how to accept/receive a HTTP Post in Go. I just want to be able to receive a file, grab its mime-type and save the file locally.
I've been searching all day but all I can find is how to send a file to some remote location but none of the examples I find cover receiving it.
Any help would be appreciated.
using Justinas' example and mixing with my existing experiment I've gotten this far but m.Post never seems to be called.
package main
import (
"fmt"
"io"
"net/http"
"os"
"github.com/codegangsta/martini"
"github.com/codegangsta/martini-contrib/render"
)
func main() {
m := martini.Classic()
m.Use(render.Renderer(render.Options{
Directory: "templates", // Specify what path to load the templates from.
Layout: "layout", // Specify a layout template. Layouts can call {{ yield }} to render the current template.
Charset: "UTF-8", // Sets encoding for json and html content-types.
}))
m.Get("/", func(r render.Render) {
fmt.Printf("%v\n", "g./")
r.HTML(200, "hello", "world")
})
m.Get("/:who", func(args martini.Params, r render.Render) {
fmt.Printf("%v\n", "g./:who")
r.HTML(200, "hello", args["who"])
})
m.Post("/up", func(w http.ResponseWriter, r *http.Request) {
fmt.Printf("%v\n", "p./up")
file, header, err := r.FormFile("file")
defer file.Close()
if err != nil {
fmt.Fprintln(w, err)
return
}
out, err := os.Create("/tmp/file")
if err != nil {
fmt.Fprintf(w, "Failed to open the file for writing")
return
}
defer out.Close()
_, err = io.Copy(out, file)
if err != nil {
fmt.Fprintln(w, err)
}
// the header contains useful info, like the original file name
fmt.Fprintf(w, "File %s uploaded successfully.", header.Filename)
})
m.Run()
}
Go's net/http server handles this pretty, using mime/multipart package behind the scenes. You only need to call r.FormFile() on your *http.Request to get a multipart.File back.
Here's a complete example. And the result of uploading a file with curl:
justinas#ubuntu /tmp curl -i -F file=#/tmp/stuff.txt http://127.0.0.1:8080/
HTTP/1.1 100 Continue
HTTP/1.1 200 OK
Date: Tue, 24 Dec 2013 20:56:07 GMT
Content-Length: 37
Content-Type: text/plain; charset=utf-8
File stuff.txt uploaded successfully.%
justinas#ubuntu /tmp cat file
kittens!

Resources