微信号:fed-talk

介绍:公众号开通于2016年,内容起于前端而不止于前端.

Go HTTP

2018-04-19 16:56 icepy

在网络编程里多数情况下,我们都在处理HTTP请求,关于请求协议的部分我推荐阅读《TCP协议》这本书,绝对值得购买。Go语言也提供了一个标准库包net/http,让开发者可以快速的处理HTTP请求,其封装的易用性,足够简单。并且,整个net包里提供了多种多样的处理模块,比如rpc等等。http包提供了HTTP客户端和服务端的实现,这让我想到了Node.js提供的http模块。


简单的Get


response, err := http.Get("http://icepy.me")
if err != nil {  
   // handle error
}
defer response.Body.Close()
body, _ := ioutil.ReadAll(response.Body) fmt.Println(string(body))


简单的Post


body := "{\"action\":20}"
res, err := http.Post("http://icepy.me", "application/json;charset=utf-8", bytes.NewBuffer([]byte(body)))
if err != nil {    fmt.Println("Fatal error ", err.Error()) }
defer res.Body.Close()
content, err := ioutil.ReadAll(res.Body)
if err != nil {    fmt.Println("Fatal error ", err.Error()) } fmt.Println(string(content))


简单的PostFrom


resp, err := http.PostForm("http://icepy.me",
url.Values{"key": {"Value"}, "id": {"123"}})
if err != nil {// handle error}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {// handle error} fmt.Println(string(body))


在上述的两个方法中,也就是说Get,Post提供了非常方便的快捷方式来处理,真正的做到了无须关心协议的细节问题,当然如果你想拥有更多的灵活性,那么就要用到http.Client和http.NewRequest了。


v := url.Values{}
v.Set("username", "xxxx")
v.Set("password", "xxxx")
body := ioutil.NopCloser(strings.NewReader(v.Encode())) client := &http.Client{}
reqest, err := http.NewRequest("POST", "http://icepy.me", body)
if err != nil {    fmt.Println("Fatal error ", err.Error()) } reqest.Header.Set("Content-Type", "application/x-www-form-urlencoded") resp, err := client.Do(reqest)
defer resp.Body.Close()
content, err := ioutil.ReadAll(resp.Body)
if err != nil {    fmt.Println("Fatal error ", err.Error()) } fmt.Println(string(content))


再来看一个文件上传的例子,不过我个人更喜欢直接传二进制数据,这个比较简单,可以直接[]byte,稍微复杂一些的就是multipart的例子。


file, err := os.Open(path)
if err != nil {
   return nil, err }
defer file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile(paramName, filepath.Base(path))
if err != nil {
   return nil, err } _, err = io.Copy(part, file)
for key, val := range params {    _ = writer.WriteField(key, val) } err = writer.Close()
if err != nil {
   return nil, err }
request, err := http.NewRequest("POST", uri, body) request.Header.Add("Content-Type", writer.FormDataContentType())
client := &http.Client{}
resp, err := client.Do(request)


如果你有细心阅读下,肯定发现了一个使用频率很高的类型url.Values,基本上不管是Get请求的参数还是Post请求的参数,如果你不想自己重复造轮子的话,可以将参数直接.Add在这个对象上,它提供了包括编码的Encode,并且如果你要提交的参数是一个数组的话,也可以很方便的通过循环.Add("arr", arr[i])的方式添加。(额外提一句,因为协议规定的如果是数组,可以如此来描述:“a=1&a=2&a=3”)


上述基本上就是HTTP的Client,接下来要说一说HTTP的Server,基本上也可以预想到,Server端的创建,也很简单。


package main
import (    
"net/http"
)
func SayHello(w http.ResponseWriter, req *http.Request) {    w.Write([]byte("Hello")) }
func main() {    http.HandleFunc("/hello", SayHello)    http.ListenAndServe(":8001", nil) }


首先定义路由规则和对应的Handle,其次是调用ListenAndServer来启动一个8001端口,我们也可以直接使用http.Server。


s := &http.Server{    
   Addr: ":8080",  
   Handler: myHandler,    
   ReadTimeout: 10 * time.Second,    
   WriteTimeout: 10 * time.Second,    
   MaxHeaderBytes: 1 << 20, } log.Fatal(s.ListenAndServe())


  • 实例化Server

  • 调用Server的ListenAndServe()

  • 调用net.Listen(“tcp”, addr)监听端口

  • 启动一个for循环,在循环体中Accept请求

  • 对每个请求实例化一个Conn,并且开启一个goroutine为这个请求进行服务go c.serve()

  • 读取每个请求的内容w, err := c.readRequest()

  • 判断header是否为空,如果没有设置handler(这个例子就没有设置handler),handler就设置为DefaultServeMux

  • 调用handler的ServeHttp

  • 在这个例子中,下面就进入到DefaultServerMux.ServeHttp

  • 根据request选择handler,并且进入到这个handler的ServeHTTP


不过,对于HTTP Server来说,就要说到如何获取参数的问题了,我们来看一下golang http.request的三个属性Form、PostForm、MultipartForm,简要说明如下,基本上你使用对应的方法,就能获取到相应的参数。


  • Form:存储了post、put和get参数,在使用之前需要调用ParseForm方法。

  • PostForm:存储了post、put参数,在使用之前需要调用ParseForm方法。

  • MultipartForm:存储了包含了文件上传的表单的post参数,在使用前需要调用ParseMultipartForm方法。




长按二维码关注公众号:

你也可以关注我的新浪微博,搜索i_icepy,很期待和大家交流

 
象尘说 更多文章 Go JSON Go 标准库 Go 如何调试你的应用程序 Go 函数也是一等公民 Go Echo Web Framework
猜您喜欢 深度学习在智能电网图像识别与故障检测中的应用 [原]django构建简易博客系统 (51) 剖析EnumSet \/ 计算机程序的思维逻辑 在现场闪耀你的光芒——携程技术中心校园宣讲会行程公布 能看病的聊天机器人,不只有大白