Http Client

Http Client 设置

设置超时机制

参考文档:https://stackoverflow.com/questions/16895294/how-to-set-timeout-for-http-get-requests-in-golang/16895878

client := http.Client{
   Timeout: 5 * time.Second,
}
client.Get(url)

Http Client 使用

Get 获取内容

package main

import (
   "fmt"
   "io/ioutil"
   "net/http"
)

func main() {

   client := &http.Client{}
   req, err := http.NewRequest("GET", 
     "https://raw.githubusercontent.com/wanglu119/HDoc/master/README.md", nil)
   resp, err := client.Do(req)
   if err != nil {
     	println("ifDnsmasq Fails: cannot connect")
   } else {
         println("ifDnsmasq Success")
         s, _ := ioutil.ReadAll(resp.Body)
         if err == nil {
             fmt.Printf("%s", s)
         }
         defer resp.Body.Close()
   }
}

输出
ifDnsmasq Success
# HDoc

发送Get和Post请求(Json ),带参数

参看文档:https://www.cnblogs.com/junneyang/p/6211190.html

package main

import (
     "bytes"
     "encoding/json"
     "fmt"
     "io/ioutil"
     "net/http"
)

type User struct {
     Name string `json:"name"`
     Age  int    `json:"age"`
}

func main() {

     resp, _ := http.Get("http://localhost:2050/?a=123456&b=aaa&b=bbb")
     defer resp.Body.Close()
     body, _ := ioutil.ReadAll(resp.Body)
     fmt.Println(string(body))

     var user User
     user.Name = "aaa"
     user.Age = 99
     if bs, err := json.Marshal(user); err == nil {
         req := bytes.NewBuffer([]byte(bs))

         body_type := "application/json;charset=utf-8"
         resp, _ = http.Post("http://localhost:2050/test", body_type, req)
         body, _ = ioutil.ReadAll(resp.Body)
         fmt.Println(string(body))
     } else {
         fmt.Println(err)
     }

     client := &http.Client{}
     request, _ := http.NewRequest("GET",
         "http://localhost:2050/?a=123456&b=aaa&b=bbb", nil)
     request.Header.Set("Connection", "keep-alive")
     response, _ := client.Do(request)
     if response.StatusCode == 200 {
         body, _ := ioutil.ReadAll(response.Body)
         fmt.Println(string(body))
     }

     req := `{"name":"test", "age":88}`
     req_new := bytes.NewBuffer([]byte(req))
     request, _ = http.NewRequest("POST", "http://localhost:2050/test", req_new)
     request.Header.Set("Content-Type", "application/json")
     response, _ = client.Do(request)
     if response.StatusCode == 200 {
         body, _ = ioutil.ReadAll(response.Body)
         fmt.Println(string(body))
     }
}


输出
It works!
{"name":"aaa","age":199}
It works!
{"name":"test","age":188}

请求配置 Basic Auth

参考文档: https://stackoverflow.com/questions/16673766/basic-http-auth-in-go

示例:

func basicAuth(username, password string) string {
  auth := username + ":" + password
  return base64.StdEncoding.EncodeToString([]byte(auth))
}

func redirectPolicyFunc(req *http.Request, via []*http.Request) error{
  req.Header.Add("Authorization","Basic " + basicAuth("username1","password123"))
  return nil
}

func main() {
  client := &http.Client{
    Jar: cookieJar,
    CheckRedirect: redirectPolicyFunc,
  }

  req, err := http.NewRequest("GET", "http://localhost/", nil)
  req.Header.Add("Authorization","Basic " + basicAuth("username1","password123")) 
  resp, err := client.Do(req)
}

发送application/x-www-form-urlencoded类型请求

参考文档: https://blog.csdn.net/liu822665/article/details/120428868

需要结合标准库urlValues结构体,比如:

postData := url.Values{}
postData.Add("name", "Chris")
postData.Add("language", "golang")

普通post请求可以直接使用http.Post方法,第二个参数为application/x-www-form-urlencoded,如:

response, err := http.Post("https://xorpay.com/api/pay/aid", 
  "application/x-www-form-urlencoded", strings.NewReader(postData.Encode()))

调用gitea示例:

func basicAuth(username, password string) string {
	auth := username + ":" + password
	return base64.StdEncoding.EncodeToString([]byte(auth))
}

func runMigrate(ctx *cli.Context) error {
	migrateUrl := fmt.Sprintf("%s%s", ctx.GlobalString("url"), "/api/v1/repos/migrate")
	fmt.Println(migrateUrl)

	postData := url.Values{}
	postData.Add("clone_addr", "http://wl.gitlab/root/simple_shell.git")
	postData.Add("repo_name", "simple_shell")
	postData.Add("auth_token", "xxxxxx")
	if ctx.IsSet("mirror") {
		postData.Add("mirror", "true")
		postData.Add("mirror_interval", "2h0m0s")
	}
	req, err := http.NewRequest("POST", migrateUrl, strings.NewReader(postData.Encode()))
	if err != nil {
		log.Fatal("migrate create req error: %v", err)
	}
	req.Header.Add("Authorization", "Basic "+basicAuth(Username, Password))
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatal("migrate error: %v", err)
		return err
	}
	bs, _ := ioutil.ReadAll(resp.Body)
	fmt.Println(string(bs))
	fmt.Println("migrate finish")
	return nil
}

http.client实现访问网站保持同一会话

参考文档: https://blog.csdn.net/qq_34068584/article/details/121559832

背景:

有些网站需要登录后才能查看或者进一步操作,比如下单等等。那在python上requests库的session可以帮助我们在这种业务场景下,只需要执行请求、而不需要每一步都写代码携带cookie。因为session帮助我们做了这件事。那么在go语言中,有没有这种类型的东西呢?

http.client 是用来创建一个客户端,模拟客户端发送请求,可以通过它来实现设置请求头部、重定向等等操作。

我们先来看看client的定义。从这段话中,可以知道 Jar这个变量的作用就是:

  • 每次发送请求时,带上cookie
  • 每次接收响应时,更新cookie
type Client struct {
	...

	// Jar specifies the cookie jar.
	//
	// The Jar is used to insert relevant cookies into every
	// outbound Request and is updated with the cookie values
	// of every inbound Response. The Jar is consulted for every
	// redirect that the Client follows.
	//
	// If Jar is nil, cookies are only sent if they are explicitly
	// set on the Request.
	Jar CookieJar

        ...
}

所以实际操作为:

// 1、首先声明一个用来管理cookie的变量jar
jar,_ := cookiejar.New(nil)

// 2、创建一个客户端
client := &http.Client{
    Jar: jar,
}

// 3、构造并发送请求1
res1,_ := client.do(req1)    //发送请求时自动带上cookie,并在返回响应时更新cookie

// 4、构造并发送请求2
res2,_ := client.do(req2)    //发送请求

示例: gitea的更新repo的mirror,需要先登录:


func getCsrf(giteaUrl string, client *http.Client) string {
	loginUrl := fmt.Sprintf("%s%s", giteaUrl, "/user/login")
	postData := url.Values{}
	postData.Add("user_name", Username)
	postData.Add("password", Password)
	postData.Add("remember", "true")

	req, err := http.NewRequest("POST", loginUrl,
		strings.NewReader(postData.Encode()))
	if err != nil {
		log.Fatal("migrate create req error: %v", err)
	}
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	resp, err := client.Do(req)
	if err != nil {
		log.Fatal("migrate error: %v", err)
	}

	_csrf := ""
	fmt.Println(resp.Cookies())
	for _, c := range resp.Cookies() {
		if c.Name == "_csrf" {
			_csrf = c.Value
		}
	}
	return _csrf
}

func runMirror(ctx *cli.Context) error {
	jar, _ := cookiejar.New(nil)
	client := &http.Client{
		Jar: jar,
	}
	giteaUrl := ctx.GlobalString("url")
	mirrorUrl := ctx.String("url")
	_csrf := getCsrf(giteaUrl, client)

	postData := url.Values{}
	postData.Add("_csrf", _csrf)
	postData.Add("action", "mirror")
	postData.Add("interval", "3h0m0s")
	mirror_address := fmt.Sprintf("%s/%s/%s.git", mirrorUrl, Username, "simple_shell")
	fmt.Println("mirror_address:", mirror_address)
	postData.Add("mirror_address", mirror_address)
	setttingUrl := fmt.Sprintf("%s/%s/%s/settings", giteaUrl, Username, "simple_shell")
	fmt.Println("setttingUrl: ", setttingUrl)
	req, err := http.NewRequest("POST", setttingUrl,
		strings.NewReader(postData.Encode()))
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal("migrate error: %v", err)
		return err
	}
	bs, _ := ioutil.ReadAll(resp.Body)
	respStr := string(bs)
	idx := strings.Index(respStr, "ui negative message flash-error")
	if idx > 0 {
		fmt.Println(string(bs)[idx : idx+100])
	}
	fmt.Println(respStr)

	return nil
}

golang 请求 https 网站跳过证书验证

参考文档:https://www.jianshu.com/p/3e9893a2eaf5

在用 Golang 访问 IPPBX 的管理页面时出现以下错误,因为证书是未经过认证的,而是自己创建的。

错误信息:Get https://192.168.0.199:8443/config/app: 
x509: certificate signed by unknown authority

所以需要忽略检查证书,以下是部分代码

import (
   "crypto/tls"
   "net/http"
   "net/http/cookiejar"
)

...
//跳过证书验证
tr := &http.Transport{
   TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}

//http cookie接口
cookieJar, _ := cookiejar.New(nil)

c := &http.Client{
   Jar:       cookieJar,
   Transport: tr,
}

c.Get("https://192.168.0.199:8443/config/app: ")
...