美文网首页
GO 语言 Web 开发实战一

GO 语言 Web 开发实战一

作者: 阿兵云原生 | 来源:发表于2023-01-14 22:56 被阅读0次
web1.jpg

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

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

HTTP 编程 Get

先来一个 小例子,简单的写一个 Get 请求

  • 拿句柄

  • 设置监听地址和端口

  • 进行数据处理

    package main
    
    import (
      "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 main
    
    import (
      "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 main
    
    import (
      "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 server
    
    func 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 main
    
    import (
      "fmt"
      "io/ioutil"
      "net/http"
      "strings"
    )
    
    //post client
    
    func 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 main

import (
    "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 看起来

image

实际处理逻辑在 func parsePostForm(r *Request) (vs url.Values, err error) {

image

这里需要注意

  • 请求提的大小上限为10MB , 需要注意请求体的大小是否会被 MaxBytesReader 限制

模板

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

感兴趣的可以琢磨一下,我们放在下一篇补充

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

image

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

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

相关文章

  • Go Web编程.epub

    【下载地址】 《Go Web编程》介绍如何用Go语言进行Web应用的开发,将Go语言的特性与Web开发实战组合到一...

  • go学习计划 2018-07-13

    go语言入门及实战 go web开发 go源码及项目阅读

  • 开发自己的区块链基础功能篇

    准备工作: 安装go开发环境 用go搭建web服务 go语言基础 安装go开发环境 到https://golang...

  • Go语言实战笔记

    Go语言实战笔记(二)| Go开发工具https://www.flysnow.org/2017/03/08/go-...

  • Go实战项目【前言】

    本项目是作为学习了Go语言基础后的一个练习实战项目。使用Go语言开发api接口,为以Flutter开发的移动端AP...

  • 浅谈Go语言函数与方法的区别

    前段时间,我们实验室用go作为后台开发语言开发了一个web项目,由于这是自己第一次使用go语言进行开发,在开发过程...

  • Golang web开发

    Goalng web开发 使用go语言来做web开发,是非常方便的。如果不使用框架,仅仅使用net/http包,也...

  • Go实战--golang中使用JWT(JSON Web Toke

    Go实战--golang中使用JWT(JSON Web Token) 生命不止,继续 go go go !!! 之...

  • 快速上手go-doudou开发单体RESTful服务

    笔者2015年开始接触go语言并采用go语言从事web项目开发至今,先后用过beego、gin、grpc等框架。这...

  • 内存泄露

    内存泄露 实战 实战Go内存泄露 - Go语言实战 - SegmentFault 思否 总结 pprof工具 使用...

网友评论

      本文标题:GO 语言 Web 开发实战一

      本文链接:https://www.haomeiwen.com/subject/euvocdtx.html