英文:
Golang html GET form method values are not getting populated
问题
我有一个服务器代码和一个HTML表单用于搜索字符串。服务器处理程序获取字符串并进行搜索。但是我在这里遇到了两个问题。
-
方法名始终为GET,即使我将其设置为POST。
-
我无法在服务器端接收到表单值。
服务器代码如下:
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)
}
我在searchHandler函数中遇到了问题。我的HTML代码如下:
{{ 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>
服务器控制台日志如下:
method: GET
Form Data :
Form Data 1: map[]
有人可以帮我解决这个问题吗?谢谢。
英文:
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
得分: 2
这是你要翻译的内容:
那是一个微妙的问题。
非常微妙地,你在searchproject的URL末尾加了一个斜杠,导致服务器发出301重定向。
表单通过POST(或GET)到/searchproject,服务器非常友好地告诉浏览器应该去/searchproject/(添加了斜杠!),浏览器以GET方式执行并在此过程中丢失了表单数据。
这个示例应该满足你的需求:
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>
`
英文:
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>
`
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论