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)
}