C++GO语言http编程

目录

01 http介绍

02 http请求格式详解

03 http请求头代码演示-postman

04 http响应格式详解

05 http响应代码演示

06 http-server代码实现

07 json编解码介绍

08 结构体标签(tag)


01 http介绍

# 三、http

## 1. 概述

编写web语言:

1. java
2. php, 现在都在尝试使用go语言重写
3. python,豆瓣
4. go语言    ===》 beego,gin两个主流的web框架



https协议:我们使用浏览器访问的时候发送的就是http请求

1. http是应用层的协议,底层还是依赖传输层:tcp(短连接),网络层(ip)

2. 无状态的,每一次请求都是独立的,下次请求需要重新建立连接

3. https:

   1. http是标准协议 ==》 明文传输,不安全

   2. https不是标准协议   ===》 https = http + ssl(非对称加密,数字证书)--》加密的

   3. 现在所有网站都会尽量要求使用https开发:安全

02 http请求格式详解

## 2. http请求报文格式



![1575433140952](C:/Users/duke/Desktop/00-go语言语法4天(总结好)/day03-socket-http/assets/1575433140952.png)

![1586155308860](assets/1586155308860.png)



一个http请求可以分为4部分:

1. 请求行:包含三部分
   1. 格式:  方法   +   URL   + 协议版本号
   2.  实例: POST  +   /chapter17/user   + HTTP/1.1
   3. 请求方法:
      1. GET:获取数据
      2. POST:上传数据(表单格式,json格式)
      3. PUT:修改数据
      4. DELETE: 用于删除数据
2. 请求头
   1. 格式:  key :value
   2. 可以有很多个键值对(包含协议自带,也包含用户自定义的)
   3. 常见重要头:
      1. Accept : 接收数据的格式
      2. User-Agent : 描述用户浏览器的信息
      3. Connection: Keep-Alive (长链接), Close(短连接)
      4. Aceept-Encoding : gzip, xxx  , 描述可以接受的编码
      5. Cookie: 由服务器设置的key=value数据,客户端下次请求的时候可以携带过来
      6. Content-Type: 
         1. appliction/-form(表示上传的数据是表单格式), 
         2. application/json(表示body的数据是json格式)
      7. 用户可以自定义的:
         1. name : Duke
         2. age : 18
3. 空行
   1. 告诉服务器,请求头结束了,用于分割
4. 请求包体(可选的)
   1. 一般在POST方法时,会配套提供BODY
   2. 在GET的时候也可以提供BODY,但是这样容易让人混淆,建议不要这样使用
   3. 上传两种数据格式:
      1. 表单: 姓名,性别,年龄
      2. json数据格式



启动tcp的server案例,使用postman发起http请求,查看http请求头信息:

```go
package main

03 http请求头代码演示-postman

启动tcp的server案例,使用postman发起http请求,查看http请求头信息:

```go
package main

import (
	"fmt"
	"net"
	"strings"
)

func main() {
	//创建监听
	ip := "127.0.0.1"
	port := 8848
	address := fmt.Sprintf("%s:%d", ip, port)

	//func Listen(network, address string) (Listener, error) {
	//net.Listen("tcp", ":8848") //简写,冒号前面默认是本机: 127.0.0.1
	listener, err := net.Listen("tcp", address)

	if err != nil {
		fmt.Println("net.Listen err:", err)
		return
	}
	fmt.Println("server start ...")

	//需求:
	// server可以接收多个连接, ====> 主go程负责监听,子go程负责数据处理
	// 每个连接可以接收处理多轮数据请求

	for {
		fmt.Println("监听中...")

		//Accept() (Conn, error)
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("listener.Accept err:", err)
			return
		}

		fmt.Println("连接建立成功!")

		go handleFunc(conn)
	}
}

04 http响应格式详解

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数据

![1586158776960](assets/1586158776960.png)


05 http响应代码演示

## 4. http client

```go
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

}

```

06 http-server代码实现

### - Server Demo

接收一个链接,而且只能发送一次数据

```go
package main

import (
	"fmt"
	"net"
	"strings"
)

func main() {
	//创建监听
	ip := "127.0.0.1"
	port := 8848
	address := fmt.Sprintf("%s:%d", ip, port)

	//func Listen(network, address string) (Listener, error) {
	//net.Listen("tcp", ":8848") //简写,冒号前面默认是本机: 127.0.0.1
	listener, err := net.Listen("tcp", address)

	if err != nil {
		fmt.Println("net.Listen err:", err)
		return
	}

	fmt.Println("监听中...")

	//Accept() (Conn, error)
	conn, err := listener.Accept()
	if err != nil {
		fmt.Println("listener.Accept err:", err)
		return
	}

	fmt.Println("连接建立成功!")

	//创建一个容器,用于接收读取到的数据
	buf := make([]byte, 1024) //使用make来创建字节切片, byte ==> uint8

	//Read(b []byte) (n int, err error)
	//cnt:真正读取client发来的数据的长度
	cnt, err := conn.Read(buf)
	if err != nil {
		fmt.Println("conn.Read err:", err)
		return
	}

	fmt.Println("Client =====> Server, 长度:", cnt, ",数据:", string(buf[0:cnt]))

	//服务器对客户端请求进行响应 ,将数据转成大写 "hello" ==> HELLO
	//func ToUpper(s string) string {
	upperData := strings.ToUpper(string(buf[0:cnt]))

	//Write(b []byte) (n int, err error)
	cnt, err = conn.Write([]byte(upperData))
	fmt.Println("Client  <====== Server, 长度:", cnt, ",数据:", upperData)

	//关闭连接
	conn.Close()
}

07 json编解码介绍

### - json编解码

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

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

```go
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)

}
```

08 结构体标签(tag)

### - 结构体标签

```go
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)

}
```

你可能感兴趣的:(http,网络协议,网络,c++)