http.FileServer is sending "404 page not found" - go

I'm trying to serve static files via http.FileServer, however it never sends back the directory I'm asking for. The code is snipped below:
func main() {
fmt.Println("Serving Files")
http.HandleFunc("/", homeFunc)
http.HandleFunc("/search", searchFunc)
http.Handle("/tmp/",
http.StripPrefix("/tmp/", http.FileServer(http.Dir("/assets"))))
http.ListenAndServe(":8080", nil)
}
When visiting mywebsite.com/tmp/, text appears saying "404 page not found." A little help in case I'm missing something would be greatly appreciated!
Edit: Here's the file architecture:
main folder
|
|-/Assets
|--(assets)
|
|-main.go

Does the directory /assets exist? Note that /assets is an absolute path, so it must be at the root of your filesystem. If you want something in the working directory where you're executing your program, you should use ./assets.

If you use relative path, you can check what your path is.
import (
"fmt"
"os"
)
dir, _ := os.Getwd()
fmt.Println("current path :" + dir)

Related

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"))))

How to serve a file to a specific url path with the FileServer function in go/golang

I need to serve an html file to localhost:8080/lvlione but the FileServer function in golang doesn't seem to work.
Here is main.go:
package main
import (
"log" //logging that the server is running and other stuff
"net/http" //serving files and stuff
)
func main() {
//servemux
server := http.NewServeMux()
//handlers that serve the home html file when called
fs := http.FileServer(http.Dir("./home"))
os := http.FileServer(http.Dir("./lvlone")) //!!this is what is broken!!
//handles paths by serving correct files
//there will be if statements down here that check if someone has won or not soon
server.Handle("/", fs)
server.Handle("/lvlione", os)
//logs that server is Listening
log.Println("Listening...")
//starts server
http.ListenAndServe(":8080", server)
}
There is a folder in this directory called lvlone with one file in it (index.html). When I point my browser to localhost:8080/lvlione it returns 404, but when it is pointed to localhost:8080 it returns the correct file.
You need to call http.StripPrefix to remove the extra lvlone from the directory path.
server.Handle("/lvlone/", http.StripPrefix("/lvlone/", os))
By default the http.FileServer assumes the path given to it is the root path, and appends the URL to it. If it is to serve a subdirectory of the virtual path, then that needs to be stripped from the path.
And note that you need to have the trailing slashes in both places.

How to get the root path of the project

I run the following code workingDir, _ := os.Getwd()
in server.go file which is under the root project and get the root path,
Now I need to move the server.go file to the following structure
myapp
src
server.go
and I want to ge the path of go/src/myapp
currently after I move the server.go under myapp->src>server.go I got path of go/src/myapp/src/server.go and I want to get the previews path ,
How should I do it in go automatically? or should I put ../ explicit in get path ?
os.Getwd() does not return your source file path. It returns program current working directory (Usually the directory that you executed your program).
Example:
Assume I have a main.go in /Users/Arman/go/src/github.com/rmaan/project/main.go that just outputs os.Getwd()
$ cd /Users/Arman/go/src/github.com/rmaan/project/
$ go run main.go
/Users/Arman/go/src/github.com/rmaan/project <nil>
If I change to other directory and execute there, result will change.
$ cd /Users/Arman/
$ go run ./go/src/github.com/rmaan/project/main.go
/Users/Arman <nil>
IMO you should explicitly pass the path you want to your program instead of trying to infer it from context (As it may change specially in production environment). Here is an example with flag package.
package main
import (
"fmt"
"flag"
)
func main() {
var myPath string
flag.StringVar(&myPath, "my-path", "/", "Provide project path as an absolute path")
flag.Parse()
fmt.Printf("provided path was %s\n", myPath)
}
then execute your program as follows:
$ cd /Users/Arman/go/src/github.com/rmaan/project/
$ go run main.go --my-path /Users/Arman/go/src/github.com/rmaan/project/
provided path was /Users/Arman/go/src/github.com/rmaan/project/
$ # or more easily
$ go run main.go --my-path `pwd`
provided path was /Users/Arman/go/src/github.com/rmaan/project/
If your project is a git repository you can also use the git rev-parse command with the --show-toplevel:
cmdOut, err := exec.Command("git", "rev-parse", "--show-toplevel").Output()
if err != nil {
assert.Fail(t, fmt.Sprintf(`Error on getting the go-kit base path: %s - %s`, err.Error(), string(cmdOut)))
return
}
fmt.Println(strings.TrimSpace(string(cmdOut)))
It'll print out the git project home path wherever in the sub path you are

How to get the directory of the package the file is in, not the current working directory

I'm making a package to make API calls to a service.
I have a test package that I use just to test the API calls and test the functions of the main package which I just include the other package into.
In my main package that I'm working on I have
ioutil.ReadFile(filepath.Abs("Filename.pub"))
Which is ok, but when I call it from my test package e.g.
/Users/####/gocode/src/github.com/testfolder go run main.go
it tells me
panic: open /Users/####/gocode/src/github.com/testfolder/public.pub: no such file or directory
The problem is, is it is looking for public.pub inside of testfolder instead of github.com/apipackage/ which is where it is.
Just to clarify this mess of words:
The API Package has a function that reads from the same directory
But because I'm including the API package and Testfolder is the CWD when I go run main.go it is instead trying to get it from the testfolder instead even though the main.go doesn't have the function and is just including it.
runtime.Caller is what you want I believe.
Here is a demonstration :
package main
import (
"fmt"
"runtime"
"path"
)
func main() {
_, filename, _, ok := runtime.Caller(0)
if !ok {
panic("No caller information")
}
fmt.Printf("Filename : %q, Dir : %q\n", filename, path.Dir(filename))
}
https://play.golang.org/p/vVa2q-Er6D
Starting from Go 1.16, you can use the embed package. This allows you to embed the files in the running go program. The referenced file needs to be at or below the embedding file. In your case, the structure would look as follows:
-- apipackage
\- public.pub
\- apipackage.go
-- testfolder
\- main.go
You can reference the file using a go directive
// apipackage.go
package apipackage
import (
"embed"
)
//go:embed public.pub
var content embed.FS
func GetText() string {
text, _ := content.ReadFile("public.pub")
return text
}
This program will run successfully regardless of where the program is executed.

Specifying template filenames for template.ParseFiles

My current directory structure looks like the following:
App
- Template
- foo.go
- foo.tmpl
- Model
- bar.go
- Another
- Directory
- baz.go
The file foo.go uses ParseFiles to read in the template file during init.
import "text/template"
var qTemplate *template.Template
func init() {
qTemplate = template.Must(template.New("temp").ParseFiles("foo.tmpl"))
}
...
Unit tests for foo.go work as expected. However, I am now trying to run unit tests for bar.go and baz.go which both import foo.go and I get a panic on trying to open foo.tmpl.
/App/Model$ go test
panic: open foo.tmpl: no such file or directory
/App/Another/Directory$ go test
panic: open foo.tmpl: no such file or directory
I've tried specifying the template name as a relative directory ("./foo.tmpl"), a full directory ("~/go/src/github.com/App/Template/foo.tmpl"), an App relative directory ("/App/Template/foo.tmpl"), and others but nothing seems to work for both cases. The unit tests fail for either bar.go or baz.go (or both).
Where should my template file be placed and how should I call ParseFiles so that it can always find the template file regardless of which directory I call go test from?
Helpful tip:
Use os.Getwd() and filepath.Join() to find the absolute path of a relative file path.
Example
// File: showPath.go
package main
import (
"fmt"
"path/filepath"
"os"
)
func main(){
cwd, _ := os.Getwd()
fmt.Println( filepath.Join( cwd, "./template/index.gtpl" ) )
}
First off, I recommend that the template folder only contain templates for presentation and not go files.
Next, to make life easier, only run files from the root project directory. This will help make the path to an file consistent throughout go files nested within sub directories. Relative file paths start from where the current working directory, which is where the program was called from.
Example to show the change in current working directory
user#user:~/go/src/test$ go run showPath.go
/home/user/go/src/test/template/index.gtpl
user#user:~/go/src/test$ cd newFolder/
user#user:~/go/src/test/newFolder$ go run ../showPath.go
/home/user/go/src/test/newFolder/template/index.gtpl
As for test files, you can run individual test files by supplying the file name.
go test foo/foo_test.go
Lastly, use a base path and the path/filepath package to form file paths.
Example:
var (
basePath = "./public"
templatePath = filepath.Join(basePath, "template")
indexFile = filepath.Join(templatePath, "index.gtpl")
)

Resources