Is http.StripPrefix necessary when serving static files in Go? - go

What's wrong with http.Handle("/static/", http.FileServer(http.Dir("")))?
The shortest example I can find looks like this:
fs := http.FileServer(http.Dir("static"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
Is http.StripPrefix necessary?

No it is not required, but if you DO NOT use it the path used to find the file will include the prefix. This is clearer with an example, so imagine your folder structure was:
main.go
static/
styles.css
And you serve the files with:
http.Handle("/static/", http.FileServer(http.Dir("")))
Then a user requesting the file at yoursite.com/static/styles.css would get the styles.css file in the static dir. But for this to work your paths must line up perfectly.
Most people prefer to do the following instead:
fs := http.FileServer(http.Dir("static"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
Because they could change their URL path to be something like /assets/ without needing to rename the static dir (or vise versa - change the local dir structure w/out updating the URL path).
TL;DR - Path prefix isn't required but is useful to break any requirements of URL paths and local directory structure matching perfectly.

Related

I don't know why stripPrefix doesn't work in golang [duplicate]

main.go
package main
import (
"net/http"
)
func main() {
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
http.ListenAndServe(":8080", nil)
}
Directory structure:
%GOPATH%/src/project_name/main.go
%GOPATH%/src/project_name/static/..files and folders ..
Even after reading the documentation I have trouble understanding what exactly http.StripPrefix does here.
1) Why can't I access localhost:8080/static if I remove http.StripPrefix?
2) What URL maps to /static folder if I remove that function?
http.StripPrefix() forwards the handling of the request to one you specify as its parameter, but before that it modifies the request URL by stripping off the specified prefix.
So for example in your case if the browser (or an HTTP client) requests the resource:
/static/example.txt
StripPrefix will cut the /static/ and forward the modified request to the handler returned by http.FileServer() so it will see that the requested resource is
/example.txt
The Handler returned by http.FileServer() will look for and serve the content of a file relative to the folder (or rather FileSystem) specified as its parameter (you specified "static" to be the root of static files).
Now since "example.txt" is in the static folder, you have to specify a relative path to that to get the corrent file path.
Another Example
This example can be found on the http package documentation page (here):
// To serve a directory on disk (/tmp) under an alternate URL
// path (/tmpfiles/), use StripPrefix to modify the request
// URL's path before the FileServer sees it:
http.Handle("/tmpfiles/",
http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("/tmp"))))
Explanation:
FileServer() is told the root of static files is "/tmp". We want the URL to start with "/tmpfiles/". So if someone requests "/tempfiles/example.txt", we want the server to send the file "/tmp/example.txt".
In order to achieve this, we have to strip "/tmpfiles" from the URL, and the remaining will be the relative path compared to the root folder "/tmp" which if we join gives:
/tmp/example.txt
Assume that
I have a file
/home/go/src/js/kor.js
Then, tell fileserve serves local directory
fs := http.FileServer(http.Dir("/home/go/src/js"))
Example 1 - root url to Filerserver root
Now file server takes "/" request as "/home/go/src/js"+"/"
http.Handle("/", fs)
Yes, http://localhost/kor.js request tells Fileserver, find kor.js in
"/home/go/src/js" + "/" + "kor.js".
we got kor.js file.
Example2 - custom url to Fileserver root
But, if we add additional resquest name.
http.Handle("/static/", fs)
Now file server takes "/static/" request as "/home/go/src/js"+"/static/"
Yes, http://localhost/static/kor.js request tells Fileserver, find kor.js in
"/home/go/src/js" + "/static/" + "kor.js".
We got 404 error.
Example 3 - custom url to Fileserver root with
so, we modify request url before Fileserver takes it with http.StripPrefix("/tmpfiles/", ...
after stripPrefix Fileserver take / instead /static/
"/home/go/src/js" + "/" + "kor.js".
got kor.js
I'll answer the two questions one by one.
Answer 1 to Question 1:
If your code is written like below:
http.Handle("/static/", http.FileServer(http.Dir("static"))
your root folder is %GOPATH%/src/project_name/static/. When you access localhost:8080/static, the URL /static will be forwarded to the handler returned by http.FileServer(). However, you have no directory or file named static in the root folder.
Answer 2 to Question 2: In general, you cannot access /static folder if you remove the http.StripPrefix(). However, if you have a directory or file named static, you can access it (exactly not the root directory you want) with the URL localhost:8080:/static.
By the way, you cannot access anything if your URL does not begin with /static, because the http.ServeMux will not redirect your request.
For anyone having issues with subdirectories, you need to add a "." because it seems it treats the path as relative only if it's a folder in the root directory of the binary.
For example
s.router.PathPrefix("/logos/").Handler(
http.StripPrefix("/logos/", http.FileServer(http.Dir("./uploads/logos/"))))
Note the "." before "/uploads"

Golang fileserver throws not found

I am trying to serve some fonts, but when i visit localhost:4000/fonts, it gives me 404 not found. my code:
fs := http.FileServer(http.Dir("./fonts"))
http.Handle("/fonts", http.StripPrefix("/fonts/", fs))
http.Handle("/", app.routes())
log.Println("Serving at localhost:4000...")
log.Fatal(http.ListenAndServe(fmt.Sprintf("localhost:%d", cfg.Port), nil))
UPDATE
if im serving from "/" and not "/fonts", it works. but i want it to work from "/fonts".
You should not strip the trailing slash after fonts since you want the result to be /file and not file.
You should also add the trailing slash to the handler path, for the same reason.
http.Handle("/fonts/", http.StripPrefix("/fonts", fs))
Both changes, as mentioned, have the purpose to leave you with a path like /somefile that is looked up against the filesevers file system.

Viper AddConfigPath only finding file in current folder "."

Have code that looks like
viper.AddConfigPath(".")
viper.AddConfigPath("$HOME/.config/myprogram")
viper.AddConfigPath("$HOME/configs")
viper.SetConfigFile("myprogram.yaml")
If I place myprogram.yaml in the current folder it works. However if I try putting it on either
$HOME/.config/myprogram$HOME/configs
The yaml file is not found. Any ideas or suggestions?
From the viper docs:
SetConfigFile explicitly defines the path, name and extension of the
config file. Viper will use this and not check any of the config
paths.
So if you use SetConfigFile the paths will be ignored. Try (as per the example):
viper.SetConfigName("myprogram")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
viper.AddConfigPath("$HOME/configs")
viper.AddConfigPath("$HOME/.config/myprogram")

How to call static HTML files

I created a static folder that contains index.html file, and in my go file, I wrote:
package main
import (
"net/http"
)
func main() {
http.Handle("/", http.FileServer(http.Dir("./static")))
http.ListenAndServe(":8482", nil)
}
And it works fine upon exploring http://localhost:8482/
I tried to write the code as:
http.Handle("/static", http.FileServer(http.Dir("./static")))
But it fails upon exploring http://localhost:8482/static with 404 error
http.Handle("/static", http.FileServer(http.Dir("./static"))) simply means, "whenever someone connects to .../static, reroute the entire request to a file server rooted at directory ./static".
However, the url is passed along to the file server as-is. In other words, the file server receives the request from the user, and believes that the user is looking for a file called "static" within the root ("./static") directory.
In fact, if you simply placed a file called "static" in your "./static" directory, going to .../static would serve that file.
So the fix requires two things:
Change the path prefix to "/static/" rather than "/static", so that all files within the static directory can be rerouted to the file server (rather than only the "/static" request)
Strip the "/static/" path prefix from the request before passing it to the file server.
Like so:
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))

File path in golang

I have a project with next structure:
|_main.go
|_config
|_config.go
|_config_test.go
|_config.json
I'm having next code line in config.go:
file, _ := os.Open("config/config.json")
When I'm executing method contained this code line from main.go all is working. But when I'm trying to execute this method from config_test.go it produces error:
open config/config.json: no such file or directory
As I understood it is a working directory issue because I'm launching same code with relative path from different directories. How can I fix this problem without using full path in config.go?
Relative paths are always resolved basis your current directory. Hence it's better to avoid relative paths.
Use command line flags or a configuration management tool (better approach) like Viper
Also according to The Twelve-Factor App your config files should be outside your project.
Eg usage with Viper:
import "github.com/spf13/viper"
func init() {
viper.SetConfigName("config")
// Config files are stored here; multiple locations can be added
viper.AddConfigPath("$HOME/configs")
errViper := viper.ReadInConfig()
if errViper != nil {
panic(errViper)
}
// Get values from config.json
val := viper.GetString("some_key")
// Use the value
}

Resources