go 网络编程

121 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第30天,点击查看活动详情

http响应格式也分为4部分:

  1. 第一部分:状态行

    1. 协议格式: 协议版本号 + 状态码 + 状态描述

    2. 实例1:HTTP/1.1 + 200 + OK

    3. 实例2:HTTP/1.1 +404 + not found

    4. 常用的状态码:

      • 1xx ===》客户端可以即系发送请求(一般感知不到)

      • 2xx ===》正常访问, 200

      • 3xx ===》重定向

      • 4xx

        • 401 ===》 未授权 not authorized
        • 404 ===> Not found
      • 5xx

        • 501 ==> Internal Error (服务器内部错误)
  2. 第二部分:响应头

    1. Content-Type : application/json
    2. Server: Apache
    3. Data : Mon, 12 Sep ...
    4. ....
  3. 第三部分:空行

    1. 用于分割,表示下面没有响应头了
  4. 第四部分:响应包体

    1. 通常是返回json数据

image.png

4. http client

package main
​
import (
    "fmt"
    "io/ioutil"
    "net/http"
)
​
func main() {
    //http包
    client := http.Client{}
​
    //func (c *Client) Get(url string) (resp *Response, err error) {
    resp, err := client.Get("https://www.baidu.com")
    if err != nil {
        fmt.Println("client.Get err:", err)
        return
    }
​
    //放在上面,内容很多
    body := resp.Body
    fmt.Println("body 111:", body)
    //func ReadAll(r io.Reader) ([]byte, error) {
    readBodyStr, err := ioutil.ReadAll(body)
    if err != nil {
        fmt.Println("read body err:", err)
        return
    }
​
    fmt.Println("body string:", string(readBodyStr))
​
    //beego, gin  ==> web框架
    ct := resp.Header.Get("Content-Type")
    date := resp.Header.Get("Date")
    server := resp.Header.Get("Server")
​
    fmt.Println("content-type:", ct)
    fmt.Println("date:", date)
    //BWS是Baidu Web Server,是百度开发的一个web服务器 大部分百度的web应用程序使用的是BWS
    fmt.Println("server:", server)
​
    url := resp.Request.URL
    code := resp.StatusCode
    status := resp.Status
​
    fmt.Println("url:", url)       //https://www.baidu.com
    fmt.Println("code:", code)     //200
    fmt.Println("status:", status) //OK
​
}
​

image.png

5. http server

package main
​
import (
    "fmt"
    "io"
    "net/http"
)
​
func main() {
    //注册路由 router
    //xxxx/user  ===> func1
    //xxxx/name  ===> func2
    //xxxx/id    ===> func3//https://127.0.0.1:8080/user, func是回调函数,用于路由的响应,这个回调函数原型是固定
    http.HandleFunc("/user", func(writer http.ResponseWriter, request *http.Request) {
        //request : ===> 包含客户端发来的数据
        fmt.Println("用户请求详情:")
        fmt.Println("request:", request)
        
        //这里是具体处理业务逻辑xxx
        
        //writer :  ===> 通过writer将数据返回给客户端
        _, _ = io.WriteString(writer, "这是/user请求返回的数据!")
    })
    //https://127.0.0.1:8080/name
    http.HandleFunc("/name", func(writer http.ResponseWriter, request *http.Request) {
        _, _ = io.WriteString(writer, "这是/name请求返回的数据!")
    })
​
    //https://127.0.0.1:8080/id
    http.HandleFunc("/id", func(writer http.ResponseWriter, request *http.Request) {
        _, _ = io.WriteString(writer, "这是/id请求返回的数据!")
    })
​
    fmt.Println("Http Server start ...")
    //func ListenAndServe(addr string, handler Handler) error {
    if err := http.ListenAndServe("127.0.0.1:8080", nil); err != nil {
        fmt.Println("http start failed, err:", err)
        return
    }
    //if err != nil {
    //  fmt.Println("http start failed, err:", err)
    //  return
    //}
}
​

image.png

6. JSON

{
    "name":"矮大紧",                           
    "sex":"man",                                
    "age":131,                              
    "girls":["金莲","凤姐","码蓉","春哥"],          
    "成绩": [2, 14, 9, 78, 96],                   
    "家电":{"彩电":"海尔", "洗衣机":"三星"},
  "stars": [
    { "name":"Faye" ,"address":" 北京 " },
    { "name":"andy" ,"address":" 香港 " },
    { "name":"eddie","address":" 台湾 " }
  ]
 }

记住,json语法要求最后一个元素后面,不能加逗号

- json编解码

在网络中传输的时候,把Student结构体,编码成json字符串,传输 ===》 结构体 ==》 字符串 ==》 编码

接收字符串,需要将字符串转换成结构体,然后操作 ==》 字符串 ==》 结构体 ==》解密

package main
​
import (
    "encoding/json"
    "fmt"
)
​
type Student struct {
    Id     int
    Name   string
    Age    int
    
    //注意,gender是小写的, 小写字母开头的,在json编码时会忽略掉
    gender string 
}
​
func main() {
    //在网络中传输的时候,把Student结构体,编码成json字符串,传输  ===》 结构体 ==》 字符串  ==》 编码
    //接收字符串,需要将字符串转换成结构体,然后操作 ==》 字符串 ==》 结构体  ==》解密
​
    lily := Student{
        Id:     1,
        Name:   "Lily",
        Age:    20,
        gender: "女士",
    }
​
    //编码(序列化),结构=》字符串
    //func Marshal(v interface{}) ([]byte, error) {
    encodeInfo, err := json.Marshal(&lily)
    if err != nil {
        fmt.Println("json.Marshal err:", err)
        return
    }
​
    fmt.Println("encodeInfo:", string(encodeInfo))
​
    //对端接收到数据
    //反序列化(解码): 字符串=》结构体var lily2 Student
​
    //func Unmarshal(data []byte, v interface{}) error {
    if err := json.Unmarshal([]byte(encodeInfo), &lily2); err != nil {
        fmt.Println("json.Unmarshal err:", err)
        return
    }
​
    fmt.Println("name:", lily2.Name)
    fmt.Println("gender:", lily2.gender)
    fmt.Println("age:", lily2.Age)
    fmt.Println("id:", lily2.Id)
​
}

image.png

- 结构体标签

package main
​
import (
    "encoding/json"
    "fmt"
)
​
type Teacher struct {
    Name    string `json:"-"`                 //==> 在使用json编码时,这个编码不参与
    Subject string `json:"Subject_name"`      //==> 在json编码时,这个字段会编码程Subject_name
    Age     int    `json:"age,string"`        //==>在json编码时,将age转成程string类型, 一定要两个字段:名字,类型,中间不能有空格
    Address string `json:"address,omitempty"` //==》在json编码时,如果这个字段是空的,那么忽略掉,不参与编码//注意,gender是小写的, 小写字母开头的,在json编码时会忽略掉
    gender string
}
​
type Master struct {
    Name    string
    Subject string
    Age     int
    Address string
    gender  string
}
​
func main() {
​
    t1 := Teacher{
        Name:    "Duke",
        Subject: "Golang",
        Age:     18,
        gender:  "Man",
        Address: "北京",
    }
​
    fmt.Println("t1:", t1)
    encodeInfo, _ := json.Marshal(&t1)
​
    fmt.Println("encodeInfo:", string(encodeInfo))
​
    //解码
    t2 := Teacher{}
    _ = json.Unmarshal(encodeInfo, &t2)
    fmt.Println("t2:", t2.Subject)
​
    m1 := Master{}
    _ = json.Unmarshal(encodeInfo, &m1)
    fmt.Println("m1:", m1)
​
}

image.png

总结:

  1. 对于结构体进行编码时(json): 字段的首字母必须大写,否则无法编码

  2. 如果json格式要求key小写,那么可以通过标签(tag)来解决

  3. tag细节:

    //==> 在使用json编码时,这个编码不参与    
    Name    string `json:"-"`            
        
    //==> 在json编码时,这个字段会编码程Subject_name
    Subject string `json:"Subject_name"`//==>在json编码时,将age转成程string类型, 一定要两个字段:名字,类型,中间不能有空格
    Age     int    `json:"age,string"`