造轮子 | golang | 简易http2拨测工具

栏目: Go · 发布时间: 5年前

内容简介:最近需要进行http2相关的工作,但是开发环境和测试环境都的curl版本都太老了不支持http2,正好最近在学习golang,于是决定自己造个轮子:用go语言实现一个建议的http2客户端,以本文记录折腾过程。完整代码地址:涉及内容:平时写程序中免不了根据输入的命令行参数来控制程序的行为,golang的标准库中提供了一个

最近需要进行http2相关的工作,但是开发环境和测试环境都的curl版本都太老了不支持http2,正好最近在学习golang,于是决定自己造个轮子:用 go 语言实现一个建议的http2客户端,以本文记录折腾过程。完整代码地址: https://github.com/yiekue/gh2c .

涉及内容:

flag
http.Client
http2

标准库的flag包

平时写程序中免不了根据输入的命令行参数来控制程序的行为,golang的标准库中提供了一个 flag包 ,用于解析命令行输入的各种 - 开头的选项,使用比较方便,免去了自己挨个解析命令行参数的麻烦。

flag包支持 boolstringint 等多种类型的选项,使用过程比较简单:

  1. flag.Bool()flag.String() 等函数定义一个flag,这些函数都有三个入参,依次是flag的 名称默认值帮助信息 ,函数的返回值是一个对应类型的 指针指针指针
  2. 在使用变量之前调用 flag.Parse() 进行解析。如果解析失败,程序会退出,并且打印各个变量的帮助信息,包含名称、默认值、和之前定义的帮助信息。 解析会在第一个非 - 开头的参数停止,在非flag参数后面的flag会被忽略
package main

import (
    "flag"
    "fmt"
    "os"
)

// 首先定义需要flag的名称、默认值、帮助信息。需要注意的是这里的函数的返回值都是指针
var help = flag.Bool("help", false, "print help info")
var version = flag.Int("v", 2, "http version 1/2")
var method = flag.String("method", "GET", "http method, GET/POST...")

func main() {
    // 首先调用Parse()函数进行解析。解析后,前面定义的各种变量就可以直接用了。
    flag.Parse()
    if *help {
        // 打印选项的默认值和帮助信息
        flag.PrintDefaults()
        os.Exit(0)
    }

    switch *version {
    case 1:
        fmt.Println("HTTP/1.1")
    case 2:
        fmt.Println("HTTP/2.0")
    default:
        flag.PrintDefaults()
        os.Exit(1)
    }

    fmt.Println("method:", *method)
}

上面这段代码的运行结果:

[~/code/test]$ go run test.go      
HTTP/2.0
method: GET

由于设置了输出帮助信息的flag默认是 false ,因此默认不会打印帮助信息,而是打印了另外两个flag的默认值。指定输出帮助信息:

[~/code/test]$ go run test.go -help
  -help
        print help info
  -method string
        http method, GET/POST... (default "GET")
  -v int
        http version 1/2 (default 2)

设置 bool 型的flag,只需要在命令行中添加这个flag即可,不需要指定它的值。而对于 string 之类的flag,就需要指定flag的值:

[~/code/test]$ go run test.go -v 1 -method "POST"
HTTP/1.1
method: POST

如果命令行中的flag在代码中没有定义或者flag的输入格式错误,程序会打印错误信息和已定义的flag信息并退出:

[~/code/test]$ go run test.go -v 1 -metho  
flag provided but not defined: -metho
Usage of /tmp/go-build852894954/b001/exe/test:
  -help
        print help info
  -method string
        http method, GET/POST... (default "GET")
  -v int
        http version 1/2 (default 2)
exit status 2

http.Client && http2

golang的标准库 net/http 中提供了一个http的客户端,可以进行简单的http操作。但是如果要使用http2就需要额外的 golang.org/x/net/http2 ,由于国内特殊的网络环境,golang.org无法直接访问到,可以到github的 镜像仓库 中下载使用。同时需要下载http2依赖的 text .

使用Client的步骤一般如下:

http.Client
client
http.NewRequest()
client.Do(req)

使用 http.Client 发起http请求的流程:

package main

import (
    "crypto/tls"
    "flag"
    "fmt"
    "golang.org/x/net/http2"
    "io/ioutil"
    "net/http"
    "os"
)

var help = flag.Bool("help", false, "print help info")
var version = flag.Int("v", 2, "http version 1/2")
var method = flag.String("method", "GET", "http method, GET/POST...")

func main() {
    flag.Parse()
    if *help {
        flag.PrintDefaults()
        os.Exit(0)
    }

    // 从命令行读取URL,URL需要在各种flag之后
    url := flag.Arg(0)
    if "" == url {
        fmt.Println("error: please input URL")
        flag.PrintDefaults()
    }

    tlsConfig := &tls.Config{
        InsecureSkipVerify: false,
    }

    // 新建一个client
    client := &http.Client{}

    // 设置http版本,默认使用http2
    switch *version {
    case 1:
        client.Transport = &http.Transport{
            TLSClientConfig: tlsConfig,
        }
    case 2:
        client.Transport = &http2.Transport{
            TLSClientConfig: tlsConfig,
        }
    default:
        fmt.Println("error: unkown http version:", *version)
        flag.PrintDefaults()
        os.Exit(1)
    }

    // 使用参数输入的请求方法和url新建一个请求
    req, err := http.NewRequest(*method, url, nil)
    if err != nil {
        fmt.Println("error: failed to create request,", err)
        flag.PrintDefaults()
        os.Exit(1)
    }
    // 设置User-Agent
    req.Header.Set("User-Agent", "GH2C")

    // 发送请求
    resp, err := client.Do(req)
    if nil != err {
        fmt.Println("error: failed to do request,", err)
        flag.PrintDefaults()
        os.Exit(1)
    }
    defer resp.Body.Close()

    // 读取响应体信息
    body, err := ioutil.ReadAll(resp.Body)
    if nil != err {
        fmt.Println("error: failed to read body.")
        flag.PrintDefaults()
        os.Exit(1)
    }

    // 答应响应头和响应体长度
    fmt.Println(">", resp.Proto, resp.Status)
    for k, vs := range resp.Header {
        for _, v := range vs {
            fmt.Printf("> %s: %s\n", k, v)
        }
    }
    fmt.Println("body.length:", len(string(body)))
}

在网上百度一个支持http2的网站,测试一把,效果如下 (域名侵删)

[~/code/test]$ go run test.go -v 2 https://www.chinacache.com/
> HTTP/2.0 200 OK
> Content-Type: text/html
> Expires: Mon, 17 Jun 2019 04:39:54 GMT
> Accept-Ranges: bytes
> Age: 19405
> Etag: W/"5cdbdbc8-2dc0"
> Last-Modified: Wed, 15 May 2019 09:28:40 GMT
> Date: Sun, 16 Jun 2019 04:39:54 GMT
> Server: nginx
> Powered-By-Chinacache: HIT from CMN-CD-b-3g3
> Cc_cache: TCP_HIT
body.length: 11712

gh2c

将在上一节的基础上增加更多的flag来增加更多的功能就成了支持http2的简易拨测工具 gh2c

  • 支持自定义头域
  • 自定义是否忽略证书
  • 更友好的输出信息
*[master][~/code/gh2c]$ ./gh2c -help            
Usage: ./gh2c -[flags] url
  -H string
        custom headers
  -HKVsep string
        used for split a custom header key and value (default ":")
  -Hsep string
        used for split custom headers (default ";")
  -body
        output response body
  -debug
        print debug info
  -help
        print help info
  -host string
        custom Host to override default (default "defaltHost")
  -method string
        http method, GET/POST... (default "GET")
  -v int
        http version 1/2 (default 2)
  -verifyCert
        enable verification of the server certificate

效果如下,默认不输出body:

*[master][~/code/gh2c]$ go run gh2c.go -v 2 -H "test:testheadker|test2:testheader2" -Hsep "|" https://example.com/
< GET HTTP/2.0 /
< Host: www.chinacache.com
< Test: testheadker
< Test2: testheader2
< User-Agent: GH2C
<
> HTTP/2.0 200 OK
> Etag: W/"5cdbdbc8-2dc0"
> Last-Modified: Wed, 15 May 2019 09:28:40 GMT
> Date: Sun, 16 Jun 2019 04:39:54 GMT
> Server: nginx
> Cc_cache: TCP_HIT
> Accept-Ranges: bytes
> Age: 11967
> Expires: Mon, 17 Jun 2019 04:39:54 GMT
> Powered-By-Chinacache: HIT from CMN-CD-b-3g3
> Content-Type: text/html
<

FIXME

在把 http2.Transport 赋值给 client.Transport 之后,使用 req.Proto 获取到的仍然是 HTTP/1.1 ,不知道怎么获取实际使用http版本。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Artificial Intelligence

Artificial Intelligence

Stuart Russell、Peter Norvig / Pearson / 2009-12-11 / USD 195.00

The long-anticipated revision of this #1 selling book offers the most comprehensive, state of the art introduction to the theory and practice of artificial intelligence for modern applications. Intell......一起来看看 《Artificial Intelligence》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

html转js在线工具
html转js在线工具

html转js在线工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具