xdm,咱明天分享一个 golang web 实战的 demo

go 的 http 包,以前都有或多或多的提到一些,也有一些笔记在咱们的历史文章中,明天来一个简略的实战

HTTP 编程 Get

先来一个 小例子,简略的写一个 Get 申请

  • 拿句柄
  • 设置监听地址和端口
  • 进行数据处理

    package mainimport (    "fmt"    "net/http")func myHandle(w http.ResponseWriter, req *http.Request){    defer req.Body.Close()    par := req.URL.Query()    fmt.Println("par :",par)    //回写数据    fmt.Fprintln(w,"name",par.Get("name"),"hobby",par.Get("hobby"))}// server 端func main() {    http.HandleFunc("/", myHandle)    err := http.ListenAndServe("0.0.0.0:9999", nil)    if err != nil{        fmt.Printf("ListenAndServe err : %v",err)        return    }}

上述的代码比较简单,就是一个简略的 http get 申请 , 次要解决数据的是 myHandle 函数

Client 客户端 实现办法 get

  • client.go

    • get办法、post办法、patch办法、head办法、put办法等等,用法基本一致
    • 设置url
    • get (或者其余办法)办法申请 url
    • 解决数据
    package mainimport (    "fmt"    "io/ioutil"    "net/http"    "net/url")//httpserver 端func main() {    //1.解决申请参数    params := url.Values{}    params.Set("name", "xiaomotong")    params.Set("hobby", "乒乓球")    //2.设置申请URL    rawUrl := "http://127.0.0.1:9999"    reqURL, err := url.ParseRequestURI(rawUrl)    if err != nil {        fmt.Printf("url.ParseRequestURI() 函数执行谬误,谬误为:%v\n", err)        return    }    //3.整合申请URL和参数    reqURL.RawQuery = params.Encode()    //4.发送HTTP申请    // reqURL.String() String将URL重构为一个非法URL字符串。    fmt.Println("Get url:", reqURL.String())    resp, err := http.Get(reqURL.String())    if err != nil {        fmt.Printf("http.Get()函数执行谬误,谬误为:%v\n", err)        return    }    defer resp.Body.Close()    //5.一次性读取响应的所有内容    body, err := ioutil.ReadAll(resp.Body)    if err != nil {        fmt.Printf("ioutil.ReadAll()函数执行出错,谬误为:%v\n", err)        return    }    fmt.Println("Response: ", string(body))}

上述编码中有应用到 reqURL.RawQuery = params.Encode()

Encode 办法将申请参数编码为 url 编码格局 ("a=123&b=345"),编码时会以键进行排序

常见状态码

  • http.StatusContinue = 100
  • http.StatusOK = 200
  • http.StatusFound = 302
  • http.StatusBadRequest = 400
  • http.StatusUnauthorized = 401
  • http.StatusForbidden = 403
  • http.StatusNotFound = 404
  • http.StatusInternalServerError = 500

HTTP 编程 Post 办法

  • 编写 server 代码 server.go
  • 设置句柄
  • 设置监听地址和端口
  • 解决相应数据

    package mainimport (    "fmt"    "io/ioutil"    "net/http")func handPost(w http.ResponseWriter, req *http.Request) {    defer req.Body.Close()    if req.Method == http.MethodPost {        b, err := ioutil.ReadAll(req.Body)        if err != nil {            fmt.Printf("ReadAll err %v", err)            return        }        fmt.Println(string(b))        resp := `{"status":"200 OK"}`        w.Write([]byte(resp))        fmt.Println("reponse post func")    } else {        fmt.Println("can't handle ", req.Method)        w.Write([]byte(http.StatusText(http.StatusBadRequest)))    }}//post serverfunc main() {    http.HandleFunc("/", handPost)    err := http.ListenAndServe("0.0.0.0:9999", nil)    if err != nil {        fmt.Printf("ListenAndServe err %v", err)        return    }}

Client 客户端 实现

  • client.go

    • get办法、post办法、patch办法、head办法、put办法等等,用法基本一致
    • 设置 url
    • post 办法申请
    • 解决数据
    package mainimport (    "fmt"    "io/ioutil"    "net/http"    "strings")//post clientfunc main() {    reqUrl := "http://127.0.0.1:9999"    contentType := "application/json"    data := `{"name":"xiaomotong","age":18}`    resp, err := http.Post(reqUrl, contentType, strings.NewReader(data))    if err != nil {        fmt.Printf("Post err %v", err)        return    }    defer resp.Body.Close()    b, err := ioutil.ReadAll(resp.Body)    if err != nil {        fmt.Printf("ReadAll err %v", err)        return    }    fmt.Println(string(b))}

上述 post 办法的编码 显著 比 get 办法的编码传参多了很多,咱们一起来看看官网源码是如何做的

func Post(url, contentType string, body io.Reader) (resp *Response, err error) {    return DefaultClient.Post(url, contentType, body)}
  • url

申请地址

  • contentType

内容的类型,例如 application/json

  • body

具体的申请体内容,此处是 io.Reader 类型的,因而咱们传入数据的时候,也须要转成这个类型

表单 form 的解决

既然是 web 相干的实战,表单必定是一个离不开的话题 , golang 外面当然有对表单的理论解决性能

  • 后面逻辑一样,服务端开启服务,监听端口
  • 每个路由对应这个处理函数
  • 处理函数中 request.ParseForm() 解析表单的具体数据
package mainimport (    "fmt"    "io"    "net/http")const form = `<html><body><form action="#" method="post" name="bar">                    <input type="text" name="in"/>                    <input type="text" name="out"/>                     <input type="submit" value="Submit"/>             </form></html></body>`func HomeServer(w http.ResponseWriter, request *http.Request) {     io.WriteString(w, "<h1>/test1 或者/test2</h1>")}func SimpleServer(w http.ResponseWriter, request *http.Request) {    io.WriteString(w, "<h1>hello, xiaomotong</h1>")}func FormServer(w http.ResponseWriter, request *http.Request) {    w.Header().Set("Content-Type", "text/html")    switch request.Method {    case "GET":        io.WriteString(w, form)    case "POST":        request.ParseForm()        fmt.Println("request.Form[in]:", request.Form["in"])        io.WriteString(w, request.Form["in"][0])        io.WriteString(w, "\n")        io.WriteString(w, request.Form["out"][0])    }}func main() {    http.HandleFunc("/", HomeServer)    http.HandleFunc("/test1", SimpleServer)    http.HandleFunc("/test2", FormServer)    err := http.ListenAndServe(":9999", nil)    if err != nil {        fmt.Printf("http.ListenAndServe()函数执行谬误,谬误为:%v\n", err)        return    }}

上述编码解析表单的逻辑是:

对于 POST、PUT 和P ATCH 申请,它会读取申请体并解析它,作为一个表单,会将后果放入r.PostFormr.Form

申请体 r.Form 中的参数优先于 URL 查问字符串值

先来看看 Request 的构造 ,参数会比拟多

type Request struct {    Method string    URL *url.URL       .... 此处省略多行 ...        ContentLength int64    //Form蕴含解析过的表单数据,包含URL字段的查问参数和PATCH、POST或PUT表单数据。    //此字段仅在调用 ParseForm 后可用    Form url.Values    //PostForm蕴含来自 PATCH、POST或PUT主体参数的解析表单数据。    //此字段仅在调用 ParseForm 后可用。    PostForm url.Values    //MultipartForm是解析的多局部表单,包含文件上传。    //该字段仅在调用 parsemmultipartform 后可用。    MultipartForm *multipart.Form    Trailer Header    RemoteAddr string    RequestURI string    TLS *tls.ConnectionState    Cancel <-chan struct{}    Response *Response    ctx context.Context}

上面是具体实现的源码,感兴趣的 xdm 能够关上 goland 看起来

理论解决逻辑在 func parsePostForm(r *Request) (vs url.Values, err error) {

这里须要留神

  • 申请提的大小下限为10MB , 须要留神申请体的大小是否会被 MaxBytesReader 限度

模板

听到 模板 这个名词应该不生疏了吧,很多组件或者语言外面都有模板的概念

感兴趣的能够推敲一下,咱们放在下一篇补充

欢送点赞,关注,珍藏

敌人们,你的反对和激励,是我保持分享,提高质量的能源

好了,本次就到这里

技术是凋谢的,咱们的心态,更应是凋谢的。拥抱变动,背阴而生,致力向前行。

我是阿兵云原生,欢送点赞关注珍藏,下次见~