zoukankan      html  css  js  c++  java
  • Golang语言HTTP客户端实践

    最近在学习Golang语言,中间遇到一个前辈指点,有一个学习原则:Learning By Doing。跟我之前学习Java的经验高度契合。在前一段时间学习洼坑中挣扎了好几天,差点就忘记这个重要的成功经验。

    那么那什么来做练习呢?当然结合当下的工作啦,所以我列了一个路线给自己,那就是从接口测试开始学起来,从功能测试到性能测试,然后掌握基本Server开发技能。

    首先,得先把HTTP接口测试常用的几个功能实现了,主要是获取HTTPrequest对象,发送请求解析响应以及HttpClient的基本配置。

    这里实现比较简单和粗浅,让我想起FunTester测试框架一开始的时候,也是从封装HttpClient.jar提供的API开始的,感慨万千。

    这里我从了Golang SDK自带的net/http包提供的HTTP相关API,虽然本身提供了http.PostForm()http.Post()以及http.Get()封装好的方法,但是在处理HTTPrequest的header和cookie处理缺乏灵活性,所以我重新将net/http封装的API进行第二次封装。其中存在几处遗漏,比如HTTPstatus的判断以及header中Content-Type自动处理,这个以后再丰富,暂时的目标就是能用。

    HTTP客户端封装

    package task
    
    import (
    	"bytes"
    	"encoding/json"
    	"fmt"
    	"io/ioutil"
    	"net/http"
    	"net/url"
    	"strings"
    	"time"
    )
    
    var Client http.Client = clients()
    
    // Res 模拟响应结构
    // @Description:
    type Res struct {
    	Have string `json:"Have"`
    }
    
    // Get 获取GET请求
    // @Description:
    // @param uri
    // @param args
    // @return *http.Request
    func Get(uri string, args map[string]interface{}) *http.Request {
    	uri = uri + ToValues(args)
    	request, _ := http.NewRequest("get", uri, nil)
    	return request
    }
    
    // PostForm POST接口form表单
    // @Description:
    // @param path
    // @param args
    // @return *http.Request
    func PostForm(path string, args map[string]interface{}) *http.Request {
    	request, _ := http.NewRequest("post", path, strings.NewReader(ToValues(args)))
    	return request
    }
    
    // PostJson POST请求,JSON参数
    // @Description:
    // @param path
    // @param args
    // @return *http.Request
    func PostJson(path string, args map[string]interface{}) *http.Request {
    	marshal, _ := json.Marshal(args)
    	request, _ := http.NewRequest("post", path, bytes.NewReader(marshal))
    
    	return request
    }
    
    // ToValues 将map解析成HTTP参数,用于GET和POST form表单
    // @Description:
    // @param args
    // @return string
    func ToValues(args map[string]interface{}) string {
    	if args != nil && len(args) > 0 {
    		params := url.Values{}
    		for k, v := range args {
    			params.Set(k, fmt.Sprintf("%v", v))
    		}
    		return params.Encode()
    	}
    	return ""
    }
    
    // Response 获取响应详情,默认[]byte格式
    // @Description:
    // @param request
    // @return []byte
    func Response(request *http.Request) []byte {
    	res, err := Client.Do(request)
    	if err != nil {
    		return nil
    	}
    	body, _ := ioutil.ReadAll(res.Body) // 读取响应 body, 返回为 []byte
    	defer res.Body.Close()
    	return body
    }
    
    // clients 初始化请求客户端
    // @Description:
    // @return http.Client
    func clients() http.Client {
    	return http.Client{
    		Timeout: time.Duration(5) * time.Second, //超时时间
    		Transport: &http.Transport{
    			MaxIdleConnsPerHost:   5,   //单个路由最大空闲连接数
    			MaxConnsPerHost:       100, //单个路由最大连接数
    			IdleConnTimeout:       90 * time.Second,
    			TLSHandshakeTimeout:   10 * time.Second,
    			ExpectContinueTimeout: 1 * time.Second,
    		},
    	}
    }
    
    // ParseRes 解析响应
    // @Description:
    // @receiver r
    // @param res
    func (r *Res) ParseRes(res []byte) {
    	json.Unmarshal(res, r)
    }
    
    // ParseRes 解析响应,将[]byte转成传入对象
    // @Description:
    // @param res
    // @param r
    //
    func ParseRes(res []byte, r interface{}) {
    	json.Unmarshal(res, r)
    }
    
    

    测试脚本

    package main
    
    import (
    	"fmt"
    	"funtester/src/task"
    	"io"
    	"log"
    	"net/http"
    	"os"
    	"time"
    )
    
    const (
    	a = iota
    	b
    	c
    	d
    	e
    )
    
    func init() {
    	os.Mkdir("./log/", 0777)
    	os.Mkdir("./long/", 0777)
    	file := "./log/" + string(time.Now().Format("20060102")) + ".log"
    	openFile, _ := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
    	writer := io.MultiWriter(os.Stdout, openFile)
    	log.SetOutput(writer)
    	log.SetFlags(log.LstdFlags | log.Lshortfile | log.Ldate)
    }
    
    func main() {
    
    	url := "http://localhost:12345/test"
    	args := map[string]interface{}{
    		"name": "FunTester",
    		"fun":  "fdsafj",
    	}
    	cookie := &http.Cookie{
    		Name:  "token",
    		Value: "fsjej09u0934jtej",
    	}
    	get := task.Get(url, args)
    	get.Header.Add("user_agent", "FunTester")
    	get.AddCookie(cookie)
    	response := task.Response(get)
    	fmt.Println(string(response))
    	form := task.PostForm(url, args)
    	bytes := task.Response(form)
    	fmt.Println(string(bytes))
    	json := task.PostJson(url, args)
    	res := task.Response(json)
    	fmt.Println(string(res))
    
    }
    
    

    控制台输出

    GOROOT=/usr/local/go #gosetup
    GOPATH=/Users/oker/go #gosetup
    /usr/local/go/bin/go build -o /private/var/folders/7b/0djfgf7j7p9ch_hgm9wx9n6w0000gn/T/GoLand/___go_build_funtester_src_m funtester/src/m #gosetup
    /private/var/folders/7b/0djfgf7j7p9ch_hgm9wx9n6w0000gn/T/GoLand/___go_build_funtester_src_m
    get请求
    post请求form表单
    post请求json表单
    
    Process finished with the exit code 0
    
    

    测试服务

    依旧采用了moco_FunTester测试框架实现。

    package com.mocofun.moco.main
    
    import com.funtester.utils.ArgsUtil
    import com.mocofun.moco.MocoServer
    
    class Share extends MocoServer {
    
        static void main(String[] args) {
            def util = new ArgsUtil(args)
            //                def server = getServerNoLog(util.getIntOrdefault(0,12345))
            def server = getServer(util.getIntOrdefault(0, 12345))
            server.get(urlStartsWith("/test")).response("get请求")
            server.post(both(urlStartsWith("/test"), existForm("fun"))).response("post请求form表单")
            server.post(both(urlStartsWith("/test"), existParams("fun"))).response("post请求json表单")
            server.get(urlStartsWith("/qps")).response(qps(textRes("恭喜到达QPS!"), 1))
    //        server.response(delay(jsonRes(getJson("Have=Fun ~ Tester !")), 1000))
            server.response("Have Fun ~ Tester !")
            def run = run(server)
            waitForKey("fan")
            run.stop()
        }
    }
    
    
    

    Have Fun ~ Tester !

  • 相关阅读:
    flex + bison multiple parsers
    Educational Codeforces Round 95 (Rated for Div. 2)
    python学习笔记 day20 序列化模块(二)
    python学习笔记 day20 常用模块(六)
    python 学习笔记 常用模块(五)
    python学习笔记 day19 常用模块(四)
    python学习笔记 day19 常用模块(三)
    python学习笔记 day19 常用模块(二)
    python学习笔记 day19 作业讲解-使用正则表达式实现计算器
    python学习笔记 day19 常用模块
  • 原文地址:https://www.cnblogs.com/FunTester/p/15384157.html
Copyright © 2011-2022 走看看