I am fairly new to Backbone and Go and trying to call a function depending on URL.
This is my code in Router from where a request is going to a Go page.
collection.fetch({
url: "/bands"
})
.done(function(data) {
console.log("hello");
});
This is my code in which I am handling all the request:
func viewHandler(w http.ResponseWriter, r *http.Request) {
fmt.println("in viewHandler")
}
func main() {
http.Handle("/", http.FileServer(http.Dir("../")))
http.HandleFunc("/bands", viewHandler)
http.ListenAndServe(":8080", nil)
}
In my Network tab the header is:
Request URL:http://localhost:8080/bands
Request Method:GET
Status Code:200 OK
Remote Address:[::1]:8080
But nothing is getting printed on console since I guess viewHandler is not getting called. What is the reason for this?
Actually your code is fine... that means almost fine. fmt.println() needs a capital "P":
func viewHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("in viewHandler")
}
When I test your code with this adjustment it prints "in viewHandler" to the terminal as expected.
Related
I'm using the following code:
func main() {
http.Handle("/", http.FileServer(http.Dir("./web-files")))
http.HandleFunc("/auth/verify", verify)
http.HandleFunc("/auth/login", login)
http.HandleFunc("/auth/signup", signup)
http.ListenAndServe(":8080", nil)
}
I'm new to go and what I want to do is that every time someone enters my webpage a function named updateCookies runs.
I've tried to use http.HandleFunc("/", updateCookies) but it didn't work cause I have already used http.Handle("/", http.FileServer(http.Dir("./web-files")))
Thanks
The handler for the your application is http.DefaultServeMux. Wrap that handler with another handler that executes your code:
// wrap returns an http.Handler that wraps another http.Handler
func wrap(h http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Before hook.
updateCookies(w, r)
h.ServeHTTP(w, r) // call the wrapped handler
// After hook.
// Nothing for now.
}
}
func main() {
http.Handle("/", http.FileServer(http.Dir("./web-files")))
http.HandleFunc("/auth/verify", verify)
http.HandleFunc("/auth/login", login)
http.HandleFunc("/auth/signup", signup)
http.ListenAndServe(":8080", wrap(http.DefaultServeMux))
}
I wrote the code to wrap an arbitrary handler because there's an easy transition to using your own http.ServeMux:
func main() {
mux := http.NewServeMux()
mux.Handle("/", http.FileServer(http.Dir("./web-files")))
mux.HandleFunc("/auth/verify", verify)
mux.HandleFunc("/auth/login", login)
mux.HandleFunc("/auth/signup", signup)
http.ListenAndServe(":8080", wrap(mux))
}
Any package can register a handler in http.DefaultServeMux. Creating your own mux ensures that you have complete control over the handlers running in your application.
http.Handle, http.HandleFunc, and http.ListenAndServe (with nil as the second argument), use http.DefaultServeMux for routing the requests to their respective handlers.
http.ListenAndServe will use the default mux ONLY when the second argument passed to it is nil. If a non-nil argument is provided then it will use that, instead of the default mux, to handle the incoming requests.
Given that http.ListenAndServe's second parameter's type is the http.Handler interface, you could simply pass updateCookies to http.ListenAndServe as the second argument (though you'll have to convert it explicitly to http.HandlerFunc) and then modify updateCookies to, at the end, pass the w and the r to the default mux.
func updateCookies(w http.ResponseWriter, r *http.Request) {
// ... [your original cookie code] ...
http.DefaultServeMux.ServeHTTP(w, r)
}
// ...
http.ListenAndServe(":8080", http.HandlerFunc(updateCookies))
I'm currently using a basic http.FileServer setup to serve a simple static site. I need to handle 404 errors with a custom not found page. I've been looking into this issue quite a bit, and I cannot determine what the best solution is.
I've seen several responses on GitHub issues along the lines of:
You can implement your own ResponseWriter which writes a custom message after WriteHeader.
It seems like this is the best approach but I'm a bit unsure of how this would actually be implemented. If there are any simple examples of this implementation, it'd be greatly appreciated!
I think this can be solved with your own middleware. You can try to open the file first and if it doesn't exist, call your own 404 handler. Otherwise just dispatch the call to the static file server in the standard library.
Here is how that could look:
package main
import (
"fmt"
"net/http"
"os"
"path"
)
func notFound(w http.ResponseWriter, r *http.Request) {
// Here you can send your custom 404 back.
fmt.Fprintf(w, "404")
}
func customNotFound(fs http.FileSystem) http.Handler {
fileServer := http.FileServer(fs)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, err := fs.Open(path.Clean(r.URL.Path)) // Do not allow path traversals.
if os.IsNotExist(err) {
notFound(w, r)
return
}
fileServer.ServeHTTP(w, r)
})
}
func main() {
http.ListenAndServe(":8080", customNotFound(http.Dir("/path/to/files")))
}
I have one Go HTTP handler like this:
mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
fmt.Println("client cancelled....................!!!!!!!!!")
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
time.Sleep(5 * time.Second)
fmt.Println("I am still running...........")
fmt.Fprint(w, "cancellation testing......")
})
The API works fine, then with curl before the request finish I terminate the curl command deliberately with Control-C, and on server side I do see the client cancelled....................!!!!!!!!! get logged out, but after a while the I am still running........... get logged out also, I thought this goroutine will be terminated immediately!
So, is this desired behaviour, or I did something wrong?
If it is expected, since whatever the goroutine will complete its work, then what is the point of the early cancellation?
If I did something wrong, please help to point me out the correct way.
You create a contex.Context that can be cancelled, which you do cancel when the client closes the connection, BUT you do not check the context and your handler does nothing differently if it is cancelled. The context only carries timeout and cancellation signals, it does not have the power nor the intent to kill / terminate goroutines. The goroutines themselves have to monitor such cancellation signals and act upon it.
So what you see is the expected output of your code.
What you want is to monitor the context, and if it is cancelled, return "immediately" from the handler.
Of course if you're "sleeping", you can't monitor the context meanwhile. So instead use time.After(), like in this example:
mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
fmt.Println("client cancelled....................!!!!!!!!!")
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
select {
case <-time.After(5 * time.Second):
fmt.Println("5 seconds elapsed, client didn't close")
case <-ctx.Done():
fmt.Println("Context closed, client closed connection?")
return
}
fmt.Fprint(w, "cancellation testing......")
})
I'm trying to pass a URL as a parameter in Golang, and I haven't been able to find a solution in all of the tutorials I've looked at. The problem is that I can only get the url to return minus a crucial forward slash.
My handler looks like this:
router.HandleFunc("/new/{url}", createURL)
So the request would look like:
www.myapp.heroku.com/new/https://www.google.com
However, the url that I results is missing a slash:
http:/www.google.com
I sure it's probably got something to do with RFC3986, but is there a way to pass in the url as it is?
After reading the other question, I understand what do you mean. Implement a kind of URL re-writer before URL goes to gorilla/mux. The function will look like:
func Rewriter(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
//Simple URL rewriter. Rewrite if it's started with API path
pathReq := r.RequestURI
if strings.HasPrefix(pathReq, "/new/") {
//Use url.QueryEscape for pre go1.8
pe := url.PathEscape(strings.TrimLeft(pathReq, "/new/"))
r.URL.Path = "/new/" + pe
r.URL.RawQuery = ""
}
h.ServeHTTP(w, r)
})
}
Wrap gorilla router when starting the http server:
r := mux.NewRouter()
// ... other handler
r.HandleFunc("/new/{original-url}", NewHandler)
//Wrap mux.Router using Rewriter
log.Fatal(http.ListenAndServe(":8080", Rewriter(r)))
Then in your URL shortener handler, the original URL can be extracted using the following code:
func NewHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
ou := vars["original-url"]
//Use url.QueryUnascape for pre go1.8
originalURL, err := url.PathUnescape(ou)
//... other processing
}
IMHO, implementing URL shortener service like this is not recommended, mainly due to incorrect use of HTTP verbs. Any GET request should not leave side effect in server e.g. no record creation in database, etc.
This particular behavior in Gorilla Mux can be changed by setting SkipClean to true.
router := mux.NewRouter()
router.SkipClean(true)
router.HandleFunc("/new/", index)
router.HandleFunc("/", index)
http.ListenAndServe(":"+port, router)
The relevant documentation can be found here.
I'm new to Golang and trying to get a basic http app running using the httprouter API. I've hit a wall with reading posted form data, despite following the advice given in another StackOverflow question.
Here's my code (minus irrelevancies):
import (
"fmt"
"net/http"
"github.com/julienschmidt/httprouter"
)
func main() {
r := httprouter.New()
r.POST("/sub", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
r.Header.Set("content-type", "text/html")
err := r.ParseForm()
if err != nil {
fmt.Fprintf(w, "<h1>Error: %s</h1>\n", err)
}
fmt.Fprintf(w, "<h1>Submitted message!</h1>\n<p>-%s-</p>\n", r.PostFormValue("msg"))
})
http.ListenAndServe("localhost:3000", r)
}
In the output, where I should see -hello-, I just see --. When I inspect the http request in Firefox, in the Form Data panel, I see msg:"hello", so why is r.PostFormValue("msg") returning a blank string?
Thanks to Volker for pointing out an error. When I commented out the line r.Header.Set("content-type", "text/html"), the problem was resolved. Perhaps that was the issue, or perhaps there was some issue with the IDE (LiteIDE) caching an old version of the code. In any case, I can now read the posted value.