1

I have a server code and a html form to search a string. Server handler gets the string and search for the same. But I am facing two issues here.

1.Method name is always GET even after I made it as POST.

2.I am Not able to receive the form value in the server end

Server code is here,

package main

import (
    "flag"
    "fmt"
    "html/template"
    "io/ioutil"
    "log"
    "net"
    "net/http"
    "regexp"
    //"bytes"
)

var (
    addr = flag.Bool("addr", false, "find open address and print to final-port.txt")
)

type Page struct {
    Title string
    Body  []byte
}

type UserInfo struct {
    Title string
    UserId   string
    UserName string
}

func (p *Page) save() error {
    filename := "projects/" + p.Title + ".txt"
    return ioutil.WriteFile(filename, p.Body, 0600)
}

func loadPage(title string) (*Page, error) {
    filename := "projects/" + title + ".txt"
    body, err := ioutil.ReadFile(filename)
    if err != nil {
        return nil, err
    }
    return &Page{Title: title, Body: body}, nil
}

//Home page handler
//Hard coding the user name
func homeHandler(w http.ResponseWriter, r *http.Request, title string) {
    p := &UserInfo{Title: "Project Tube",UserId: "dxa132330", UserName: "Dinesh Appavoo"}
    renderTemplate(w, "home", p)
}

//Search project handler
func searchHandler(w http.ResponseWriter, r *http.Request, title string) {
    fmt.Println("method:", r.Method) //get request method
    r.ParseForm()
    if r.Method == "GET" {
    form_data := r.FormValue("form_data")
    fmt.Println("Form Data : ",form_data)
    fmt.Println("Form Data  1: ",r.Form)
    for _,val := range r.FormValue("search_string") {
        fmt.Println("Search string: ", val)
    }

    } else {
        r.ParseForm()
        fmt.Println("Search string:", r.FormValue("search_string"))
    }
    p := &UserInfo{Title: "Project Tube",UserId: "dxa132330", UserName: "Dinesh Appavoo"}
    renderTemplate(w, "searchproject", p)
}

var templates = template.Must(template.ParseFiles("home.html", "editproject.html", "viewproject.html", "searchproject.html", "header.html", "footer.html"))


func renderTemplate(w http.ResponseWriter, tmpl string, p interface{}) {

    //If you use variables other than the struct u r passing as p, then "multiple response.WriteHeader calls" error may occur. Make sure you pass 
    //all variables in the struct even they are in the header.html embedded 
    if err := templates.ExecuteTemplate(w, tmpl+".html", p); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }
}

//URL validation
var validPath = regexp.MustCompile("^/(home|editproject|saveproject|viewproject|searchproject)/(|[a-zA-Z0-9]+)$")

func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        m := validPath.FindStringSubmatch(r.URL.Path)
        if m == nil {
            http.NotFound(w, r)
            return
        }
        fn(w, r, m[2])
    }
}

func main() {
    flag.Parse()
    TestConn()
    http.HandleFunc("/home/", makeHandler(homeHandler))
    http.HandleFunc("/searchproject/", makeHandler(searchHandler))
    http.Handle("/resources/", http.StripPrefix("/resources/", http.FileServer(http.Dir("resources"))))

    if *addr {
        l, err := net.Listen("tcp", "127.0.0.1:0")
        if err != nil {
            log.Fatal(err)
        }
        err = ioutil.WriteFile("final-port.txt", []byte(l.Addr().String()), 0644)
        if err != nil {
            log.Fatal(err)
        }
        s := &http.Server{}
        s.Serve(l)
        return
    }

    http.ListenAndServe(":8080", nil)
}

I am facing issues in the searchHandler function. And my html code is here

{{ template "header.html" . }}
<br><br>
<div class="container">
    <form action="/searchproject" method="GET">
        <div class="form-group">
            <input type="text" class="form-control" name="search_string">
        </div>
        <button type="submit" class="btn btn-success">Search</button>
    </form>
</div>

server console log is as follows,

method: GET
Form Data :
Form Data  1:  map[]

Could anyone help me on this? Thanks.

1
  • There's no reason to get receive a GET instead of a POST in your code. Make certain your browser is not caching old versions while you're modifying the source. If that doesn't help, please try to make a minimal example to demonstrate what's happening. Commented Mar 12, 2015 at 18:50

1 Answer 1

2

Thats a subtle problem you have there.

Very subtly you have a trailing slash on the searchproject url that causes a 301 redirect to be issued from the server.

The form does the POST (or GET) to /searchproject and the server, quite kindly says that the browser should go to /searchproject/ (trailing slash added !), which the browser does as a GET and looses the form data in the process.

This example does what you need I think :

package main

import (
    "fmt"
    "net/http"
)

func searchHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Printf("%+v\n", r)
    fmt.Fprintln(w, "OK")
}

func homeHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, SEARCH_PAGE)
}

func main() {
    http.HandleFunc("/", homeHandler)
    http.HandleFunc("/searchproject", searchHandler)
    http.ListenAndServe(":8080", nil)
}

const SEARCH_PAGE = `
<html>
<body>
    <form action="searchproject" method="POST">
            <input type="text" name="search_string">
            <input type="submit" value="Search">
    </form>
</body>
</html>
`
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.