httpRequest

Get请求

  • 直接用 http.Get
package main

import (

  "fmt"

  "io"

  "net/http"

)

func main(){

  res,err := http.Get("http://127.0.0.1");

  if err != nil{

     fmt.Println(err)
     return

  }

defer res.Body.Close()

 

  data,err := io.ReadAll(res.Body)   //获取响应体必须这么写,返回的是byte类型

  if err!=nil{

     fmt.Println(err)

     return

}

 

  //clearly

  fmt.Println(len(data))    //body content,is byte type

  fmt.Println(res.Status)     //like status code

  fmt.Println(res.StatusCode)   //status code

  fmt.Println(res.Proto)      //internet protocol

  header:=res.Header    //http response header

fmt.Println("contentlength",res.ContentLength)  //response body contentlength,value -1 indicates that the length is unknown

 

  server,ok:=header["Server"];

  if (ok){

     fmt.Println(server);

  }

  for key,value:=range header{  //go through header map and get the key&&value

     fmt.Println(key,"--->",value) 

  }

}
  • 手动new request

跟进 http.Get() 可以看到,其实是new 了一个request,然后用 DefaultClient.Do()

一般我们都是手动new

	method := "GET"
	url := "http://www.xxx.com"
	req, err := http.NewRequest(method, url, nil)
	if err != nil {
		return
	}
	cli := http.Client{}
	resp, err := cli.Do(req)

添加请求头/代理/超时

package main

 

import (

  "fmt"

  "io/ioutil"

  "net/http"

  "net/url"

  "time"

)

func main(){

 

  //根据源码,设置代理的时候必须写成一个函数

  proxy := func (*http.Request)(*url.URL,error)  {

     return url.Parse("http://127.0.0.1:8080")

}

 

  client := &http.Client{

     Timeout: 5*time.Second,                   //超时时间,还有更精细的设置,看文档

     Transport: &http.Transport{Proxy:proxy},     //设置代理

}

 

	requesGet,_:=http.NewRequest("GET","http://127.0.0.1",nil)
  requesGet.Header.Add("test","It is only a test!");

 	 res,err := client.Do(requesGet)  //返回*response类型

  if err != nil{

     fmt.Println(err);

}

 

  //下面和前面一样了,操作*response即可

defer res.Body.Close()

  data,err := ioutil.ReadAll(res.Body)

  if err != nil{

     fmt.Println(err)
 }

fmt.Println(len(data))

}

POST请求

  • 第一种
package main

import (
    "fmt"
    "net/http"
	"net/url"
)

func main(){
    var req_url string = "http://127.0.0.1";
    var data = url.Values{}   //请求值
    data.Add("username","admin");
    data.Add("passwd","password");
    res,err := http.PostForm(req_url,data) //postform其实也是newrequest封装的
    if err!=nil{
        fmt.Println(err)
        return
}
	//其实postform是post的简写
    
    defer res.Body.Close()
    fmt.Println(res.StatusCode)
}
  • 第二种
package main

import (
    "fmt"
    "net/http"
    "strings"
)
func main(){
	client := &http.Client{};

    //请求体的处理,一般就用strings.NewReader
    req,err :=http.NewRequest("POST","http://127.0.0.1",strings.NewReader("name=dale"));
    if err != nil{
        return;
    }
    //req.Header.Set("Content-Type","application/x-www-form-urlencoded") 看情况
    res,err := client.Do(req)
    if err != nil{
        panic(err)
    }
    defer res.Body.Close()
    fmt.Println(res.StatusCode)
}

自定义请求

package main

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"
)

func main() {
	//请求参数
	form := url.Values{}
	form.Add("key", "value")
	//代理到burp查看详细
	proxy := func(*http.Request) (*url.URL, error) {
		return url.Parse("http://127.0.0.1:8080")
	}
	//构建一个Delete请求
	req,	 err := http.NewRequest("DELETE", "http://www.baidu.com/robots.txt", strings.NewReader(form.Encode()))
	if err != nil {
		return
	}

	client := &http.Client{
		Timeout:   10 * time.Second,
		Transport: &http.Transport{Proxy: proxy},
	}
	resp, err := client.Do(req)
	if err != nil {
		return
	}
	data, err := io.ReadAll(resp.Body)
	if err != nil{
		return
	}
	fmt.Println(string(data))
}

JSON解析

数据大概长这样:

  • 方法一
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"
)

type myData struct{
	ErrorCode int `json:"errorCode"`
	Message string `json:"message"`
	Data Temp2		`json:"data"`
	Success bool	`json:"success"`
}

type Temp2 struct{
	Result []Result `json:"results"`
	Curson string `json:"cursor"`	
	HasMore bool `json:"hasMore"`
}

type Result struct{
	TopicID int `json:"topicId"`
	Type int `json:"type"`
}

func main() {
	req,err := http.NewRequest("GET","http://175.178.49.147/api/topic/topics",nil)
	if err != nil{
		fmt.Println(err)
		return 
	}
	
	client := &http.Client{
		Timeout: 10 *time.Second,
	}
	resp,err := client.Do(req)
	if err != nil{
		fmt.Println(err)
		return
	}
	defer resp.Body.Close()
	data,err := io.ReadAll(resp.Body)
	if err != nil{
		return
	}
	var v = new(myData)
	err = json.Unmarshal(data,v)
	if err != nil{
		fmt.Println(err)
		return 
	}
	//Get Data
	fmt.Printf("%+v",v)
	fmt.Println(v.Data.Curson)
	for _,item:= range v.Data.Result{
		fmt.Println(item)
	}	

}

下一层就用一个结构体表示,不需要每一个字段都写出来

  • 方法二

使用Decoder解析,就是换一种写法

func main() {
	req, err := http.NewRequest("GET", "http://175.178.49.147/api/topic/topics", nil)
	if err != nil {
		fmt.Println(err)
		return
	}

	client := &http.Client{
		Timeout: 10 * time.Second,
	}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
		return
	}

	var v = new(myData)
    
    //这里换一种写法
    defer resp.Body.Close()
	err = json.NewDecoder(resp.Body).Decode(v)
	if err != nil {
		fmt.Println(err)
		return
	}
	//Get Data
	fmt.Printf("%+v", v)
	fmt.Println(v.Data.Curson)
	for _, item := range v.Data.Result {
		fmt.Println(item)
	}

}

请求体复用

我现在要发送是个相同的 POST 包

错误实例:

	method := "POST"
	url := "http://www.xxx.com"
	body := strings.NewReader(`{"name":"jack"}`)
	req, err := http.NewRequest(method, url, body)
	if err != nil {
		return
	}
	cli := http.Client{}

	for i := 0; i < 10; i++ {
		cli.Do(req)
	}

第一次请求之后,body就被关闭了(body为io.Reader),后续请求都读不到body,会报错

两种解决方法:

  • 请求体复用
  • 每次都new一个新的request
// 请求体复用
//
//
for i := 0; i < 10; i++ {
		//此时就重置了body
		io.NopCloser(body)
		cli.Do(req)
	}

//new request
//
//
	method := "POST"
	url := "http://www.xxx.com"
	//直接到外面循环
	for i := 0; i < 10; i++ {
		body := strings.NewReader(`{"name":"jack"}`)
		req, err := http.NewRequest(method, url, body)
		if err != nil {
			return
		}
		cli := http.Client{}
		cli.Do(req)
	}

Reference