• go语言 http学习


    net/http库学习

    概念

    处理器

    • 处理器:拥有ServeHTTP方法的接口(任何类型)

    签名:ServeHTTP(http.ResponseWriter, *http.Request)

    1. ResponseWriter接口
    2. 指向Request结构的指针
    • ServeMux结构(拥有ServeHTTP方法,如上签名)
    • Handler结构
    • 多路复用器 DefaultServeMux(ServeMux结构的实例)

    处理器函数

    • 与处理器有相同行为的函数
      • 与ServeHTTP方法有相同的签名

    ServeMux

    • HTTP请求多路复用器
      • 接收HTTP请求__并根据请求中的__URL__将请求重定向到正确的__处理器
    • ServeMux结构也实现了ServeHTTP方法,它也是一个处理器
      • ServeMux的ServeHTTP方法,调用与被请求URL相对应的__处理器__的ServeHTTP方法

    最简单的Web服务器

    import "fmt"
    import "net/http"
    
    // 处理器
    type HelloHandler struct{}
    func ( h *HelloHandler) ServeHTTP ( w http.ResponseWriter, r * http.Request){
        fmt.Fprintf( w, "Hello" )
    }
    
    // 处理器函数
    func hello( w http.ResponseWriter, r * http.Request){
        fmt.Fprintf( w, "Hello" )
    }
        
    func main () {
    	server := http.Server{
    		Addr: "127.0.0.1:8080",
    		//Handler: nil, //可以指定处理器
    	}
    	fmt.Println("hello https://tool.lu/")
    	//http.ListenAndServe(":8181", nil)
    	//server.ListenAndServe()
    	
    	// 将 处理器 绑定到DefaultServeMux 
    	// Handle是ServeMux结构的方法,而DefaultServeMux是ServeMux的实例
    	//hello := HelloHandler{}
    	//http.Handle("/hello", &hello)
    	
    	// 将函数转换为处理器,再将处理器绑定到DefaultServeMux
    	//http.HandleFunc( "/hello", hello )
    	
    	//使用默认的多路复用器DefaultServeMux作为处理器
    	server.ListenAndServeTLS("cert.pem", "key.pem")
    }
    

    http客户端

    http.NewRequest

    • htp.Client -> http.request(http.NewRequest) -> client.Do(request)
    • NewRequest(method, urlStr string, body io.Reader)
      • 第三个参数是请求的body中的内容
    • request.Header.Set
      • 向请求首部添加信息

    http.Clinet

    • cient结构api
      • client.get/post/postform
    • client参数配置
      • Transport RoundTripper
      • CheckRedirect func(req Request, via []Request) error
      • Jar CookieJar
      • Timeout time.Duration
    • Transport
      • 为了控制代理、安全套接层设置、保持连接、压缩、超时设置和其它设定,需要创建一个Transport
      • MaxIdleConns
        • 对所有host的最大连接数量
      • MaxIdleConnsPerHost
        • 对__每个host__的最大连接数量
    tr := &http.Transport{  
         TLSClientConfig:    &tls.Config{RootCAs: pool},  
         DisableCompression: true,  
    }  
    client := &http.Client{Transport: tr}  
    resp, err := client.Get("https://example.com")
    
    
    tr := &http.Transport{
                MaxIdleConnsPerHost: 1000, //是否表示最多建立1000个连接?
    }
    client := &http.Client{
            Transport: tr,
    }
    

    http

    • http.Get/Post/Postform

    resp.Body.Close()

    • 当客户端使用完response body后必须使用close对其进行关闭

    httplib学习

    https://github.com/astaxie/beego

    概念

    • httplib库主要用来模拟客户端发送HTTP请求
    • 类似于curl工具

    使用

    • request对象
    • debug输出
    • 设置clinet的TLS信息

    gin学习

    package tests
    
    import (
    	"encoding/json"
    	"fmt"
    	"github.com/astaxie/beego/httplib"
    	"github.com/gin-gonic/gin"
    	"io/ioutil"
    	"log"
    	"net/http"
    	"strings"
    	"testing"
    	"time"
    )
    
    func handleTestGet(c *gin.Context) {
    	c.String(http.StatusOK, "test get OK")
    }
    
    func handleTestPost(c *gin.Context) {
    	c.JSON(http.StatusOK, gin.H{"code": 1, "message": "test post OK"})
    }
    
    func handleParam(c *gin.Context) {
    	name := c.Param("name")
    	passwd := c.Param("passwd")
    	c.String(http.StatusOK, "name: %s, passwd: %s", name, passwd)
    }
    
    func handleQuery(c *gin.Context) {
    	name := c.Query("name")
    	passwd := c.Query("passwd")
    	c.String(http.StatusOK, "name: %s, passwd: %s", name, passwd)
    }
    
    func handleHTTPLib(c *gin.Context) {
    	c.IndentedJSON(200, gin.H{"code": 1, "data": "ok"})
    }
    
    func runtBasicGinServer() {
    	fmt.Print("aa")
    
    	router := gin.Default()
    
    	router.GET("/test_get", handleTestGet)
    	router.POST("/test_post", handleTestPost)
    
    	router.GET("/test_param/:name/*passwd", handleParam)
    
    	router.GET("/test_query", handleQuery)
    
    	router.GET("/test_httplib", handleHTTPLib)
    
    	group := router.Group("/v1")
    	group.GET("/test_group", handleTestGet)
    
    	router.Run(":6543")
    }
    
    func printGetResp(resp *http.Response) {
    	defer resp.Body.Close()
    	bodyBytes, err := ioutil.ReadAll(resp.Body)
    	if err != nil {
    		log.Printf("read body err %s
    ", err.Error())
    	}
    	log.Printf("resp body is: %+v
    ", string(bodyBytes))
    }
    
    func printPostResp(resp *http.Response) {
    	defer resp.Body.Close()
    	bodyBytes, err := ioutil.ReadAll(resp.Body)
    	if err != nil {
    		log.Printf("read body err %s
    ", err.Error())
    	}
    	type body struct {
    		Code    int    `json:"code"`
    		Message string `json:"message"`
    	}
    	respBody := body{}
    	err = json.Unmarshal(bodyBytes, &respBody)
    	if err != nil {
    		log.Printf("unmarshal body err %s
    ", err.Error())
    	}
    	log.Printf("resp body is: %+v
    ", respBody)
    }
    
    func TestBasicClient(t *testing.T) {
    	go runtBasicGinServer()
    	time.Sleep(time.Second * 5)
    	resp, err := http.Get("http://127.0.0.1:6543/test_get")
    	if err != nil {
    		log.Printf("get resp err %s
    ", err.Error())
    	}
    	printGetResp(resp)
    
    	resp, err = http.Post("http://127.0.0.1:6543/test_post", "", strings.NewReader(""))
    	if err != nil {
    		log.Printf("get resp err %s
    ", err.Error())
    	}
    	printPostResp(resp)
    
    	resp, err = http.Get("http://127.0.0.1:6543/test_param/name=Bob/passwd=1234")
    	if err != nil {
    		log.Printf("get resp err %s
    ", err.Error())
    	}
    	printGetResp(resp)
    
    	resp, err = http.Get("http://127.0.0.1:6543/test_param/name=Bob/")
    	if err != nil {
    		log.Printf("get resp err %s
    ", err.Error())
    	}
    	printGetResp(resp)
    
    	resp, err = http.Get("http://127.0.0.1:6543/test_param/name=Bob")
    	if err != nil {
    		log.Printf("get resp err %s
    ", err.Error())
    	}
    	printGetResp(resp)
    
    	resp, err = http.Get("http://127.0.0.1:6543/test_query?name=Alice&passwd=123")
    	if err != nil {
    		log.Printf("get resp err %s
    ", err.Error())
    	}
    	printGetResp(resp)
    
    	resp, err = http.Get("http://127.0.0.1:6543/v1/test_group")
    	if err != nil {
    		log.Printf("get resp err %s
    ", err.Error())
    	}
    	printGetResp(resp)
    
    	res := struct {
    		Code    int    `json:"code"`
    		Message string `json:"message"`
    	}{}
    
    	if err := httplib.Get("http://127.0.0.1:6543/test_httplib").ToJSON(&res); err != nil {
    		log.Println(err.Error())
    	}
    
    	log.Printf("%+v", res)
    
    }
    
    func TestReuseHTTPLink(t *testing.T) {
    	go runtBasicGinServer()
    	time.Sleep(time.Second * 5)
    
    	tr := &http.Transport{
    		MaxIdleConnsPerHost: 100,
    		MaxIdleConns:        100,
    	}
    	c := http.Client{Transport: tr}
    
    	url := "http://127.0.0.1:6543/test_get"
    
    	/*
    		连接数,
    		当前 无剩余 可用连接时 会创建;
    		当前 有剩余 可用连接则 不创建
    	*/
    	// use channel to control http port numbers
    	ch := make(chan struct{}, 100)
    
    	for i := 0; i < 5000; i++ {
    		go func(i int) {
    			ch <- struct{}{}
    			defer func() {
    				<-ch
    			}()
    			req, err := http.NewRequest("GET", url, nil)
    
    			if err != nil {
    				log.Printf("get req error %s", err.Error())
    			}
    			resp, err := c.Do(req)
    			if err != nil {
    				log.Printf("do req error %s", err.Error())
    			}
    			defer resp.Body.Close()
    
    			bodyBytes, err := ioutil.ReadAll(resp.Body)
    			if err != nil {
    				log.Printf("read body error %s", err.Error())
    			}
    
    			log.Printf("%d body: %s", i, string(bodyBytes))
    		}(i)
    		//time.Sleep(time.Microsecond * 50)
    		//time.Sleep(time.Microsecond * 50)
    	}
    
    	time.Sleep(time.Second * 10)
    }
    
    func TestSeqDo(t *testing.T) {
    	go runtBasicGinServer()
    	time.Sleep(time.Second * 5)
    
    	c := http.Client{}
    
    	url := "http://127.0.0.1:6543/test_get"
    
    	/*
    		defaul reuse http link
    		there is one link to 6543
    	*/
    	for i := 0; i < 5000; i++ {
    		req, err := http.NewRequest("GET", url, nil)
    
    		if err != nil {
    			log.Printf("get req error %s", err.Error())
    		}
    		resp, err := c.Do(req)
    		if err != nil {
    			log.Printf("do req error %s", err.Error())
    		}
    		defer resp.Body.Close()
    
    		bodyBytes, err := ioutil.ReadAll(resp.Body)
    		if err != nil {
    			log.Printf("read body error %s", err.Error())
    		}
    
    		log.Printf("%d body: %s", i, string(bodyBytes))
    	}
    
    	time.Sleep(time.Second * 10)
    }
    
    func TestSeqHTTPLib(t *testing.T) {
    	go runtBasicGinServer()
    	time.Sleep(time.Second * 5)
    
    	url := "http://127.0.0.1:6543/test_get"
    
    	/*
    		???netstat -anp | grep 6543 | grep ESTABLISHED
    	*/
    	for i := 0; i < 5000; i++ {
    		bodyString, err := httplib.Get(url).String()
    		if err != nil {
    			log.Printf("httplib get error %s", err.Error())
    		}
    		log.Printf("%d body: %s", i, bodyString)
    	}
    
    	time.Sleep(time.Second * 10)
    }
    
    

    binding学习

    github.com/gin-gonic/gin/binding

    HTTPS服务

    参考文献

    《Go Web 编程》
    Go语言_HTTP包
    深入Go语言网络库的基础实现
    golang中发送http请求的几种常见情况
    Go语言net/http 解读
    go net/http Client使用——长连接客户端的使用
    https://github.com/astaxie/beego
    beego中文文档

  • 相关阅读:
    Qt Q3DScatter中元素的移动和旋转
    Qt QtDataVisualization Q3DScatter绘制散点图
    Qt qwtplot3d根据时间采集多条曲线
    Qt QWT3D 之 三维动态曲线的实现
    Qt 数据可视化之3D图形
    Vagrant在虚拟机Centos7上安装Docker
    VirtualBox+Vagrant环境搭建
    VMware安装Centos7超详细过程(图文)
    上传excel表格批量导入数据到数据库
    IP协议包头分析
  • 原文地址:https://www.cnblogs.com/wangzhiyi/p/9194035.html
Copyright © 2020-2023  润新知