import ( "fmt" "log" "net/http" "strings" ) func Main() { http.HandleFunc("/", sayHello) // 設置訪問的路由 err := http.ListenAndServe(":9090", nil) //設置監聽的端口 if err != nil { log.Fatal("listenAndServe Err:", err) } } func sayHello(w http.ResponseWriter, r *http.Request) { r.ParseForm() //解析參數,默認是不會解析的 fmt.Println(r.Form) fmt.Println("url_long", r.Form["url_long"]) fmt.Println("path:", r.URL.Path) fmt.Println("scheme:", r.URL.Scheme) for k, v := range r.Form { s := "key:" + k + ", " s += "value:" + strings.Join(v, ",") fmt.Println(s) } fmt.Fprintf(w, "hello") }
import ( "fmt" "net/http" ) type MyMux struct { } func (p *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/" { sayHello(w, r) return } http.NotFound(w, r) return } func sayHello(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "hello") } func Main() { mux := &MyMux{} http.ListenAndServe(":9090", mux) }
註冊:css
http.Handle("/tpl/css/", http.FileServer(http.Dir("./")))
請求時處理:html
http.ServeFile()
Or:web
fileHandler := http.FileServer(http.Dir("static/websocket")) http.Handle("/wsfile/", http.StripPrefix("/wsfile/", fileHandler))
訪問時使用 http://localhost:9090/wsfile/ws.html
正則表達式
Or:數組
func StaticServer(addr string, paths map[string]string) { servers := make(map[string]http.Handler, len(paths)) for pattern, path := range paths { servers[pattern] = http.FileServer(http.Dir(path)) } http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { urlPath := r.URL.Path for pattern, handler := range servers { if strings.HasPrefix(urlPath, pattern) { http.StripPrefix(pattern, handler).ServeHTTP(w, r) return } } http.NotFound(w, r) }) log.Fatal(http.ListenAndServe(addr, nil)) }
經過對http包的分析以後,如今讓咱們來梳理一下整個的代碼執行過程。瀏覽器
首先調用Http.HandleFunc服務器
按順序作了幾件事:websocket
其次調用http.ListenAndServe(":9090", nil)cookie
按順序作了幾件事情:session
http.Redirect(w, r, "/", 302)
302 可換成 http.StatusFound
http.NotFount(w, r)
import ( "fmt" "log" "net/http" "net/http/httputil" "strings" "time" ) func main() { server := http.Server{ Addr: ":8080", Handler: NewReverseProxyHandler(), ReadTimeout: 5 * time.Second, WriteTimeout: 120 * time.Second, MaxHeaderBytes: 1 << 20, } log.Fatal(server.ListenAndServe()) } type ReverseProxyHandler struct { innerProxy *httputil.ReverseProxy } func NewReverseProxyHandler() *ReverseProxyHandler { innerProxy := &httputil.ReverseProxy{ Director: redirectRequest, } return &ReverseProxyHandler{ innerProxy: innerProxy, } } func (handler *ReverseProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { path := r.URL.Path if !strings.HasPrefix(path, "/index") { w.WriteHeader(http.StatusBadRequest) w.Write([]byte("bad request")) return } fmt.Println(path) handler.innerProxy.ServeHTTP(w, r) } func redirectRequest(r *http.Request) { u := r.URL u.Host = "127.0.0.1:9099" u.Scheme = "http" }
在src/web/form下新建一個login.gtpl
<html> <head> <title></title> </head> <body> <form action="/login" method="post"> 用戶名:<input type="text" name="username"> 密碼:<input type="password" name="password"> <input type="submit" value="登錄"> </form> </body> </html>
編寫處理邏輯
package form import ( "fmt" "html/template" "log" "net/http" ) func login(w http.ResponseWriter, r *http.Request) { fmt.Println("method:", r.Method) if r.Method == "GET" { t, err := template.ParseFiles("form/login.gtpl") if err != nil { fmt.Println("parseFiles:", err) log.Fatal("parseFiles:", err) return } fmt.Println(t.Name()) t.Execute(w, nil) } else { r.ParseForm() fmt.Println("username:", r.Form["username"]) fmt.Println("password", r.Form["password"]) } } func Main() { http.HandleFunc("/login", login) err := http.ListenAndServe(":9090", nil) if err != nil { log.Fatal("listenAndServe:", err) } }
在瀏覽器訪問http://localhost:9090/login
r.Form[「name」]
獲取的是數組
r.Form.Get(「name」)
若是不存在則返回空字符串,但只能返回第一個name的值
getint, err := strconv.Atoi(r.Form.Get("age")) if err != nil { //數字轉化出錯了,那麼可能就不是數字 }
或者使用正則表達式:
if m, _ := regexp.MatchString("^[0-9]+$", r.Form.Get("age")); !m { return false }
if m, _ := regexp.MatchString("^\\p{Han}+$", r.Form.Get("realname")); !m { return false }
if m, _ := regexp.MatchString("^[a-zA-Z]+$", r.Form.Get("engname")); !m { return false }
if m, _ := regexp.MatchString(`^([\w\.\_]{2,10})@(\w{1,}).([a-z]{2,4})$`, r.Form.Get("email")); !m { fmt.Println("no") }else{ fmt.Println("yes") }
if m, _ := regexp.MatchString(`^(1[3|4|5|8][0-9]\d{4,8})$`, r.Form.Get("mobile")); !m { return false }
t, err := template.ParseFiles("form/login.gtpl") // 相對於運行的exe程序 if err != nil { log.Fatal("parseFiles:", err) return } t.Execute(w, nil)
func HTMLEscape(w io.Writer, b []byte) //把b進行轉義以後寫到w func HTMLEscapeString(s string) string //轉義s以後返回結果字符串 func HTMLEscaper(args ...interface{}) string //支持多個參數一塊兒轉義,返回結果字符串
示例:
import ( "fmt" "html/template" "net/http" ) func Main() { http.HandleFunc("/", escapeTest) err := http.ListenAndServe(":9090", nil) if err != nil { fmt.Println("ListenAndServe Err:", err) } } func escapeTest(w http.ResponseWriter, r *http.Request) { text := template.HTMLEscapeString("<script>alert('aaa');</script>") // 輸出到客戶端 w.Write([]byte(text)) // 或者 //template.HTMLEscape(w, []byte("<script>alert('aaa');</script>")) }
輸出爲:
<script>alert('aaa');</script>
t, _ := template.New("foo").Parse(`{{define "T"}}hello,{{.}}!{{end}}`) t.ExecuteTemplate(w, "T", "<script>alert('aaa');</script>")
輸出爲:
hello,<script>alert('aaa');</script>!
但若是使用template.HTML進行強轉後則:
t.ExecuteTemplate(w, "T", template.HTML("<script>alert('aaa');</script>"))
輸出爲:
hello,<script>alert('aaa');</script>!
template.HTMLEscape(w, []byte("<script>alert('aaa');</script>"))
這種方式獲得的結果是轉義了的。
可是下面獲得的倒是彈窗:
w.Write([]byte(template.HTML("<script>alert('aaa');</script>")))
package upload import ( "fmt" "html/template" "io" "net/http" "os" ) func Main() { http.HandleFunc("/", index) http.HandleFunc("/upload", upload) err := http.ListenAndServe(":9090", nil) if err != nil { fmt.Println("ListenAndServe Err:", err) } } func index(w http.ResponseWriter, r *http.Request) { t, err := template.ParseFiles("upload/upload.gtpl") if err != nil { fmt.Println("index() Err:", err) return } t.Execute(w, nil) } func upload(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { return } r.ParseMultipartForm(32 << 20) // 32MB // 得到上傳文件的句柄 // FormFile會自動調用ParseMultipartForm(),默認內存32MB file, header, err := r.FormFile("uploadfile") // uploadfile是<input>的name if err != nil { fmt.Println("upload() Err:", err) return } defer file.Close() // 輸出header fmt.Fprintf(w, "%v", header.Header) // 轉儲文件[upload目錄必須存在] f, err := os.OpenFile("./upload/"+header.Filename, os.O_WRONLY|os.O_CREATE, 0666) if err != nil { fmt.Println("os.OpenFile() Err:", err) return } defer f.Close() io.Copy(f, file) }
package upload import ( "bytes" "fmt" "io" "io/ioutil" "mime/multipart" "net/http" "os" ) func postFile(filename, url string) error { bodyBuf := &bytes.Buffer{} bodyWriter := multipart.NewWriter(bodyBuf) // 關鍵的一步 fileWriter, err := bodyWriter.CreateFormFile("uploadfile", filename) if err != nil { fmt.Println("error writing to buffer") return err } //打開文件句柄操做 fh, err := os.Open(filename) if err != nil { fmt.Println("error opening file") return err } defer fh.Close() //iocopy _, err = io.Copy(fileWriter, fh) if err != nil { return err } contentType := bodyWriter.FormDataContentType() bodyWriter.Close() resp, err := http.Post(url, contentType, bodyBuf) if err != nil { return err } defer resp.Body.Close() resp_body, err := ioutil.ReadAll(resp.Body) if err != nil { return err } fmt.Println(resp.Status) fmt.Println(string(resp_body)) return nil } func ClientPostFile() { target_url := "http://localhost:9090/upload" filename := "./魔方公式.txt" postFile(filename, target_url) }
客戶端:
window.open("/admin/account/download/" + time[0] + "/" + time[1], "_blank");
服務端:
c.Header("Content-Disposition", `attachment;filename="`+url.QueryEscape(fileName)+`"`) c.File("recordStatisFiles/" + fileName)
Content-Type在ServerFile中會自動添加。
import ( "log" "net/http" "time" ) func Main() { http.HandleFunc("/w", writeCookie) http.HandleFunc("/r", readCookie) err := http.ListenAndServe(":9090", nil) if err != nil { log.Fatal("listener:", err) } } func writeCookie(w http.ResponseWriter, r *http.Request) { expiration := time.Now() expiration = expiration.AddDate(0, 0, 1) cookie := http.Cookie{Name: "name", Value: "chen", Expires: expiration} http.SetCookie(w, &cookie) } func readCookie(w http.ResponseWriter, r *http.Request) { cookies := r.Cookies() for _, cookie := range cookies { w.Write([]byte(cookie.String() + "\n")) } cookie, _ := r.Cookie("name") w.Write([]byte("name的cookie:" + cookie.String())) }