net-http介绍

.
├─ ClientGet
│ └── main.go // 发送get请求
├─ ClientPost
│ └── main.go // 发送post请求
├─ Server
│ └── main.go // web服务

Go语言内置的net/http包十分的优秀,提供了HTTP客户端和服务端的实现。

1.Server/main.go

  • 客户端 请求信息 封装在http.Request对象中
  • 服务端返回的 响应报文 会被保存在http.Response结构体中
  • 发送给客户端响应的并不是http.Response,而是通过http.ResponseWriter接口来实现的
方法签名 描述
Header() 用户设置或获取响应头信息
Write() 用于写入数据到响应体
WriteHeader() 用于设置响应状态码,若不调用则默认状态码为200 OK。
package main

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
)

// 定义入参结构体
type Data struct {
	Speak string `json:"speak"`
}

// 处理get请求
func dealGetReqHandler(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query()
	//获取请求参数两种方法
	if len(query["name"]) > 0 {
		name := query["name"][0]
		log.Printf("1.通过map中切片的下标获取:%s\n", name)
	}
	name2 := query.Get("name") //没有的话就会返回空值
	log.Printf("2.通过Get方法获取:%s\n", name2)

	data := &Data{
		name2 + "是笨蛋",
	}
	//响应json数据:序列化了一下data对象,并写入响应体w中
	json.NewEncoder(w).Encode(data)
        //也可以w.Write([]byte(··json数据··))
}

// 处理post请求
func dealPostReqHandler(w http.ResponseWriter, r *http.Request) {
	//获取请求体数据
	bodyByte, err := io.ReadAll(r.Body)
	if err != nil {
		w.Write([]byte(err.Error()))
	}
	//转成结构体示范,为了可以更好的处理数据,而不是必须转结构体才能json返回
	bodyStr := string(bodyByte)
	data := &Data{}
	json.Unmarshal([]byte(bodyStr), &data)
	log.Printf("从post请求体中获取到的数据:%s\n", data.Speak)
	//返回响应内容
	data.Speak = data.Speak + "是笨蛋"

	//返回响应体内容
	json.NewEncoder(w).Encode(data)
}

// 启动http服务
func main() {
	//注册全局路由
	http.HandleFunc("/req/post", dealPostReqHandler)
	http.HandleFunc("/req/get", dealGetReqHandler)
	http.ListenAndServe(":8000", nil)
}
  1. 一个路由对应一个handler:/api/xxx对应的是一个处理方法
  2. http.ResponseWriter用来响应内容
  3. *http.Request用来拿到请求头或者请求参数

测试

fei@feideMBP Server % go run main.go
2024/10/02 02:43:58 1.通过map中切片的下标获取:虞锋
2024/10/02 02:43:58 2.通过Get方法获取:虞锋
2024/10/02 02:44:04 从post请求体中获取到的数据:虞锋

fei@feideMBP ~ % curl http://127.0.0.1:8000/req/get?name=虞锋
{"speak":"虞锋是笨蛋"}
fei@feideMBP ~ % curl -X POST http://127.0.0.1:8000/req/post \
-H 'Content-Type: application/json' \
-d '{"speak":"虞锋"}'
{"speak":"虞锋是笨蛋"}

2.ClientGet/main.go

package main

import (
	"io"
	"log"
	"net/http"
	"net/url"
)

func main() {
	apiUrl := "http://localhost:8000/req/get"
	//定义url参数
	data := url.Values{}
	data.Set("name", "httpGet-root")
	//组装url
	u, err := url.ParseRequestURI(apiUrl)
	if err != nil {
		panic(err)
	}
	u.RawQuery = data.Encode()
	log.Printf("请求路由为:%s\n", u.String())

	//发起请求
	resp, err := http.Get(u.String())
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	//读取
	byteBody, _ := io.ReadAll(resp.Body)
	log.Printf("返回数据为:%s\n", string(byteBody))
}

测试

# 启动server
fei@feideMBP Server % go run main.go 
2024/10/02 03:39:08 1.通过map中切片的下标获取:httpGet-root
2024/10/02 03:39:08 2.通过Get方法获取:httpGet-root

# 启动getclient
fei@feideMBP ClientGet % go run main.go 
2024/10/02 03:39:08 请求路由为:http://localhost:8000/req/get?name=httpGet-root
2024/10/02 03:39:08 返回数据为:{"speak":"httpGet-root是笨蛋"}

3.ClientPost/main.go

package main

import (
	"io"
	"log"
	"net/http"
	"strings"
)

func main() {
	apiUrl := "http://localhost:8000/req/post"
	//定义请求体及header
	contentType := "application/json"
	data := `{"speak":"httpPost"}`
	resp, err := http.Post(apiUrl, contentType, strings.NewReader(data))
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	//读取
	byteBody, _ := io.ReadAll(resp.Body)
	log.Printf("返回数据为:%s\n", string(byteBody))
}

测试

# 启动server
fei@feideMBP Server % go run main.go
2024/10/02 03:51:39 从post请求体中获取到的数据:httpPost

# 启动postclient
fei@feideMBP ClientPost % go run main.go
2024/10/02 03:51:39 返回数据为:{"speak":"httpPost是笨蛋"}

Last updated 02 Oct 2024, 03:56 +0800 . history