"Blank response" NotFoundHandler not working Gorilla - go

I am trying to debug 404-not-found by writing a custom not-found handler. Here is my code.
package main
import (
"database/sql"
"encoding/json"
"fmt"
"log"
"net/http"
"github.com/coopernurse/gorp"
_ "github.com/go-sql-driver/mysql"
"github.com/gorilla/mux"
)
func main() {
// Create a MUX
r := mux.NewRouter()
http.Handle("/", r)
r.NotFoundHandler = http.HandlerFunc(NotFound)
// Static
r.PathPrefix("/app").HandlerFunc(uiAppHandler)
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal(err)
}
}
func NotFound(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "custom 404")
}
func uiAppHandler(w http.ResponseWriter, r *http.Request) {
repoFrontend1 := "/UI/KD/WebContent"
http.StripPrefix("/app/", http.FileServer(http.Dir(repoFrontend1)))
}
I am getting a blank response for both existing and non-existing files. I guess NotFound is not getting triggered because of my "/" handler. Then how do I handle notFound for http.Dir?
Here is my directory structure

The response from uiAppHandler is blank because the function does not write to the response w. You should register the file server handler directly with the mux instead of trying to create a handler:
r.PathPrefix("/app").Handler(http.StripPrefix("/app/", http.FileServer(http.Dir(repoFrontend1))))
The mux passes all requests with the prefix "/app" to the handler registered for that prefix. All requests with that prefix are found as far as the mux is concerned. The http.FileServer or whatever you register for that prefix is responsible for generating the 404 response.

Related

how to create a reverse proxy in golang

I wants to make a reverse proxy in golang using net package from stl library. Used httputil for creating reverse proxy. But when I make request to the proxy server it return 404 error.
Here is the proxy server code
package main
import (
"log"
"net/http"
"net/http/httputil"
"net/url"
)
func main() {
demoUrl , err := url.Parse("http://localhost:1000/run/")
if err!=nil{
log.Fatal(err)
return
}
proxy := httputil.NewSingleHostReverseProxy(demoUrl)
http.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
proxy.ServeHTTP(rw, r)
})
http.ListenAndServe(":2000", nil)
}
Here is the origin server code :
package main
import (
"net/http"
)
func main(){
http.HandleFunc("/run", func(w http.ResponseWriter, r *http.Request){
w.Write([]byte("I am running"))
})
http.ListenAndServe(":1000", nil)
}
Please tell what I am missing here and how to fix the bug! Please
The router doesn't match.
this will be working as expected.
...
func main(){
http.HandleFunc("/run/", func(w http.ResponseWriter, r *http.Request){
w.Write([]byte("I am running"))
})
http.ListenAndServe(":1000", nil)
}
...

How to get the file name of a posted binary data using Golang?

I am posting a csv file as a binary file using Postman REST API client. I need to get the filename of the uploaded file.
Here is a simple example of posting a csv file as binary data and storing the binary data as a csv file.
package main
import ( //"fmt"
"net/http"
"os"
"io"
"log"
"github.com/gorilla/mux"
)
func uploadData(w http.ResponseWriter, req *http.Request) {
file, err := os.Create("hello.csv")
_, err = io.Copy(file, req.Body)
_ = err
}
func main(){
router := mux.NewRouter()
router.HandleFunc("/parse", uploadData).Methods("POST")
log.Fatal(http.ListenAndServe(":8000", router))
}
You could use an encoding, such as form-data, which includes the filename to upload file with postman. This will help you can send multipart/form-data request to server. After that you can extract file name from server side.
From server side
func uploadData(w http.ResponseWriter, req *http.Request) {
_, header, _ := req.FormFile("demo")
fmt.Println(header.Filename)
}
Since, there is no filename associated with a HTTP request body. You have to send the filename in your URL if you want to get the filename.
package main
import (
"net/http"
"os"
"io"
"log"
"github.com/gorilla/mux"
)
func uploadData(w http.ResponseWriter, req *http.Request) {
params := mux.Vars(req)
file, err := os.Create(params["fileName"])
_, err = io.Copy(file, req.Body)
if err!=nil{
log.Printf("Error while Posting data")
}
}
func main(){
router := mux.NewRouter()
router.HandleFunc("/upload/{fileName}", uploadData).Methods("POST")
log.Fatal(http.ListenAndServe(":8000", router))
}

Gorilla Mux not handling my path

When I use the default router from http everything works, but if I use the router from gorilla/mux instead, I get a 404 page with the body 404 page not found. As shown in the samples below, everything else is exactly the same.
Why doesn't the gorilla/mux router work like this?
Working correctly, using http routing:
package main
import "net/http"
func simplestPossible(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("MWE says OK"))
}
func main() {
http.HandleFunc("/", simplestPossible)
http.ListenAndServe(":8000", nil)
}
Not working, using gorilla/mux routing:
package main
import "net/http"
import "github.com/gorilla/mux"
func simplestPossible(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("MWE says OK"))
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/", simplestPossible)
http.ListenAndServe(":8000", nil)
}
You must pass your handler to http package (ListenAndServe):
http.ListenAndServe(":8000", r)

Go simple API Gateway proxy

I've been searching all over the internet how to do this, but I haven't been able to find it. I'm trying to build a simple API gateway using Go and Martini for my system that has a few microservices with REST interfaces running. For example, I have my users service running on 192.168.2.8:8000, and I want to access it through /users
So my API gateway would look something like this:
package main
import (
"github.com/codegangsta/martini"
"net/http"
)
func main(){
app := martini.Classic()
app.Get("/users/:resource", func(req *http.Request, res http.ResponseWriter){
//proxy to http://192.168.2.8:8000/:resource
})
app.Run()
}
edit
I've got something working, but all i see is [vhost v2] release 2.2.5:
package main
import(
"net/url"
"net/http"
"net/http/httputil"
"github.com/codegangsta/martini"
"fmt"
)
func main() {
remote, err := url.Parse("http://127.0.0.1:3000")
if err != nil {
panic(err)
}
proxy := httputil.NewSingleHostReverseProxy(remote)
app := martini.Classic()
app.Get("/users/**", handler(proxy))
app.RunOnAddr(":4000")
}
func handler(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request, martini.Params) {
return func(w http.ResponseWriter, r *http.Request, params martini.Params) {
fmt.Println(params)
r.URL.Path = "/authorize"
p.ServeHTTP(w, r)
}
}
edit 2
This only seems to be a problem when using it directly through the browser, XMLHttpRequest works just fine
stdlib version
package main
import (
"log"
"net/http"
"net/http/httputil"
"net/url"
)
func main() {
target, err := url.Parse("http://192.168.2.8:8000")
if err != nil {
log.Fatal(err)
}
http.Handle("/users/", http.StripPrefix("/users/", httputil.NewSingleHostReverseProxy(target)))
http.Handle("/public/", http.StripPrefix("/public/", http.FileServer(http.Dir("./Documents"))))
log.Fatal(http.ListenAndServe(":8080", nil))
}
Wrap http.StripPrefix with a function that logs before calling it if you need logging.

gorilla mux router handlers

I can not get the gorilla mux to work..
When requesting http://www.localhost:9000 this is returned by the web server 404 page not found
But this works http://localhost:9000/ and prints Hello world
package main
import (
"net/http"
"fmt"
"log"
"github.com/gorilla/mux"
)
func Handler(w http.ResponseWriter, r *http.Request){
fmt.Fprint(w, "Hello world")
}
func main(){
r := mux.NewRouter()
r.Host("www.localhost")
r.HandleFunc("/", Handler)
err := http.ListenAndServe(":9000", r)
if err != nil {
log.Fatal("ListenAndServe error: ", err)
}
}
You want to be able to support both localhost and www.localhost
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/mux"
)
func Handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello world")
}
func main() {
r := mux.NewRouter()
r.Host("www.localhost").Path("/").HandlerFunc(Handler)
r.HandleFunc("/", Handler)
err := http.ListenAndServe(":9000", r)
if err != nil {
log.Fatal("ListenAndServe error: ", err)
}
}
If you read the documentation carefully, you'll notice that r.Host() is just another pattern matching function. It doesn't set any global rule for that router.
if you want to make that rule to be inherited you'll need to use a subrouter:
subrouter := r.Host("www.localhost").Subrouter()
then you use "subrouter" in place of "r"

Resources