Go红队开发—web网络编程

立山  论坛元老 | 2025-3-12 12:34:41 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 2011|帖子 2011|积分 6033

目录

web网络编程

tips:这一章的铺垫比较重要,这章过后就是一些安全工具如何编写以及一些poc、exp的工具编写。
Req

简朴的请求

  • 客户端创建
  • 请求设置
  1. func reqHttp() {
  2.     client := req.C()       //客户端创建
  3.     res, err := client.R(). //请求设置,这个点的意思链式调用,后续在控制请求中会讲
  4.                 Get("https://httpbin.org/uuid")
  5.     if err != nil {
  6.         log.Println("请求失败:", err)
  7.     }
  8.     fmt.Println(res)
  9. }
复制代码
快速请求


  • MustGet
    测试使用可以,正式开发不发起使用,可控性差
  1. // 快速使用,一般用在test的时候
  2. func testHttp() {
  3.   
  4.     resp := req.MustGet("https://httpbin.org/uuid") //这里就是发起了一次请求
  5.     fmt.Println(resp.String())                      //第一种打印*req.Response类型的响应体
  6.     fmt.Println(string(resp.Bytes()))               //第二种打印*req.Response类型的响应体
  7. }
复制代码
调试

DevMode

DevMode是直接开启全局调试,自动打印出来
  1. // 调试模式
  2. func devModeReq() {
  3.     //使用req进行请求,所以req的调试模式也是在req启动
  4.     req.DevMode()                                   //开启调试模式,就会打印出来请求的过程以及响应内容
  5.     req.SetCommonBasicAuth("username", "password"). //设置用户名和密码
  6.                             SetTimeout(5 * time.Second). //设置超时时间
  7.                             SetUserAgent("my-ua")
  8.     resp := req.MustGet("https://httpbin.org/uuid")
  9.     //没有开启调试模式但是想打印的话就正常打印
  10.     fmt.Println(resp.String())        //第一种打印*req.Response类型的响应体
  11.     fmt.Println(string(resp.Bytes())) //第二种打印*req.Response类型的响应体
  12. }
复制代码
DebugLog

DebugLog 是跟踪请求的过程

他可以看到你整个请求的过程,重定向的信息等等
  1. // 查看请求的过程发生了什么
  2. func deLog() {
  3.     client := req.C().
  4.         EnableDebugLog() //开启DebugLog
  5.     client.R().Get("http://baidu.com/s?wd=req")
  6. }
复制代码
TraceInfo瓶颈分析

trace跟踪信息
  1. func traceReq() {
  2.     // Enable trace at request level
  3.     client := req.C()
  4.     resp, err := client.R().
  5.         EnableTrace(). //开启瓶颈分析
  6.         Get("https://api.github.com/users/imroc")
  7.     if err != nil {
  8.         log.Fatal(err)
  9.     }
  10.     trace := resp.TraceInfo()  //trace跟踪信息
  11.     fmt.Println(trace.Blame()) //分析总结(请求减慢的原因归咎)
  12.   
  13.     fmt.Println(trace) // 打印内容
  14. }
复制代码
控制请求与响应

控制请求的字段内容

这里做一个了解,反面会详细说一下作用范围,这里就过一遍即可,知道哪些字段可控(其实都可控)
  1. func controlReq() {
  2.   
  3.     client := req.C().
  4.         SetUserAgent("my-ua"). //设置ua头,在client中设置,在下面的R()中设置不了
  5.         //EnableDumpAllToFile("log.txt") //将请求的信息写到该文件中
  6.         //捕获请求和响应,
  7.         // 想要看的更加详细就可以开启dump所有内容,
  8.         // 就能够看到我们是不是真的改变了请求内容
  9.         EnableDumpAll()
  10.   
  11.     parms := map[string]string{
  12.         "a": "123",
  13.         "b": "hello",
  14.     }
  15.   
  16.     resp, err := client.R(). //拿到请求体
  17.                     SetPathParam("usernamae", "imroc"). //设置请求路径,用username作为占位符
  18.                     SetPathParam("xxx", "test").        //再次设置,用xxx作为占位符
  19.                     SetQueryParam("a", "12").           //设置请求参数,a=12
  20.                     SetQueryParams(parms).              //用map来作为请求参数,用于多个参数的时候
  21.                     SetHeader("mycookie", "test").      //设置请求头
  22.                     SetHeader("mysession", "test2").    //设置请求头
  23.                     SetBody("body=world").              //设置请求体
  24.                     Get("https://httpbin.org/uuid")
  25.   
  26.     //以上设置暂时在初期阶段够用了。
  27.     if err != nil {
  28.         log.Println("请求出错:", err)
  29.     }
  30.     fmt.Println(resp)
  31. }
复制代码
控制调试打印的内容


  • SetCommonDumpOptions:控制输出的内容
  • EnableDumpAllToFile:dump到文件中
输出的log2.txt文件内容如下
  1. // 控制调试打印的内容
  2. // 全局应用
  3. func controlDevOptions() {
  4.     client := req.C()
  5.     opt := &req.DumpOptions{
  6.         Output:         os.Stdout, //标准输出
  7.         RequestHeader:  false,     //不输出请求头
  8.         RequestBody:    false,     //不输出请求体
  9.         ResponseHeader: true,      //输出响应头
  10.         ResponseBody:   true,      //输出响应体
  11.         Async:          false,     //不进行异步输出
  12.     }
  13.     client.SetCommonDumpOptions(opt).
  14.         EnableDumpAllToFile("log2.txt")
  15.     client.R().Get("https://httpbin.org/uuid")
  16. }
复制代码
分开dump请求与响应部分


  • var bufReq, bufResp bytes.Buffer:需要用变量来吸收请求与响应不同部分
  • SetDumpOptions:控制dump导出部分
  1. // 分别打印请求与响应部分
  2. // 在R中控制调试打印的内容,只作用与本次R请求,与上面的client直接全局设置的不同
  3. func controlReqRespOutPut() {
  4.     client := req.C()
  5.     var bufReq, bufResp bytes.Buffer
  6.     client.R().
  7.         // 不开启的话就会导致无法转储出去单独打印请求体响应体
  8.         EnableDump(). //EnableDump启用转储,包括请求和响应的所有内容。
  9.         SetDumpOptions(&req.DumpOptions{
  10.             RequestOutput:  &bufReq,  //将请求体输出到这里
  11.             ResponseOutput: &bufResp, //将响应体输出到这里
  12.             RequestHeader:  true,
  13.             RequestBody:    true,
  14.             ResponseHeader: true,
  15.             ResponseBody:   true,
  16.         }).
  17.         SetBody("body=hello+world!").
  18.         Get("https://httpbin.org/uuid")
  19.   
  20.     fmt.Println("请求体")
  21.     fmt.Println(bufReq.String())
  22.     fmt.Println("响应体")
  23.     fmt.Println(bufResp.String())
  24. }
复制代码
请求体设置

SetBody 可以接受恣意类型
PS: EnableDumpAllWithoutResponse由于开启了调试模式,所以会打印许多东西,但是可以忽略响应打印出来结果,所以这函数就是忽略响应结果,只看请求。

在编写一些poc/exp的时间可能需要在body部分,需要加入一些结构体或者map数据,他会根据你设置的content-type来判定剖析成json还是xml格式,如果都不设置的话他会默认将这些类型剖析为json数据body。

添加上content-type类型后就自动转了,比较方便(反面另有更方便的)


  • SetBodyXXX
    不用设置content-type也能直接转想要的格式了

以下是代码:
  1. // 设置请求体中的一些骚姿势
  2. func setbodyHttp() {
  3.     type test struct {
  4.         Name string
  5.         Age  int
  6.     }
  7.     t := test{
  8.         Name: "zhangsan",
  9.         Age:  123,
  10.     }
  11.     client := req.C().DevMode().EnableDumpAllWithoutResponse()
  12.     client.R().
  13.         SetBody(t).
  14.         SetContentType("application/xml").
  15.         Get("https://httpbin.org/uuid")
  16.   
  17.     client2 := req.C().DevMode().EnableDumpAllWithoutResponse()
  18.     client2.R().
  19.         SetBodyXmlMarshal(t).
  20.         Get("https://httpbin.org/uuid")
  21.   
  22. }
复制代码
作用范围级别

在设置请求参数的时间,有分两种作用范围设置,一种全局(客户端级别),另一种就是只作用与这一个client的对象(请求级别)。
以下就只管快速过为妙,上面学的时间已经有许多函数都用过了,没须要花太多时间,知道即可,下面作为一个知识字典,以后方便查阅。
请记住:

  • 用req.C().R()来设置的请求级别
  • 用req.C()来设置的是全局级别(也即客户端级别client)
设置参数查询

请求级别:

  • SetQueryParam:SetQueryParam("test", "123") 即 httpxxx?test=123
    设置多个的时间仅仅对末了一个设置的生效
  • SetQueryParams:SetQueryParams吸收map类型设置多个变量,由于map的键唯一,所以多个同名的话也只会作用一个。
  • SetQueryString:直接给查询参数即可,SetQueryString("test1=123&test2=456")
    这个不会产生什么重复覆盖题目,字符串给啥他就拼接到你url中去
  • AddQueryParam:AddQueryParam("key", "value1") 如果该参数已存在,它不会覆盖原有的值,这个一般用在你暂时需要添加什么查询参数的时间可以用,而且不会覆盖原有的同名键值
全局级别:

  • SetCommonQueryParam
  • SetCommonQueryParams
  • SetCommonQueryString
  • AddCommonQueryParam
URL 路径参数

请求级别:

  • SetPathParam:SetPathParam("username", "zhangsan")
  • SetPathParams:吸收map类型
全局级别:

  • SetCommonPathParam
  • SetCommonPathParams
表单请求设置

请求级别:

  • SetFormData:吸收map类型,但是同一个键只能有一个
  • SetFormDataFromValues::
    代码如下所示,但是注意的是url.Values是net/url包,所以要注意这个url不是我定义的,拿来就用即可。
  1. client3 := req.C().DevMode().EnableDumpAllWithoutResponse()
  2. v := url.Values{
  3.         "p": []string{"hello", "world", "!"},
  4. }
  5. client3.R().
  6.         SetFormDataFromValues(v).
  7.         Post("https://httpbin.org/post")
复制代码


  • multipart ⽅式提交表单:EnableForceMultipart
  1. client3 := req.C().DevMode().EnableDumpAllWithoutResponse()
  2. v := url.Values{
  3.         "p": []string{"hello", "world", "!"},
  4. }
  5. client3.R().
  6.         EnableForceMultipart().
  7.         SetFormDataFromValues(v).
  8.         Post("https://httpbin.org/post")
复制代码

全局级别:

  • SetCommonFormData
  • SetCommonFormDataFromValues
请求头设置

请求级别:

  • SetHeader:自动将你传进的header键的首字母大写
  • SetHeaders:吸收map类型,自动将你传进的header键的首字母大写
  • SetHeaderNonCanonical:你给什么样就输出什么样,不会自动给你首字母大写
  • SetHeadersNonCanonical:你给什么样就输出什么样,不会自动给你首字母大写
  • SetHeaderOrder:控制header的顺序,由于有的服务端可能会对header的顺序判定是否允许请求,设置了SetHeaderOrder,他就会按照你给定的顺序进行排序请求过去。
  1. request.SetHeaderOrder(
  2.         "cookie",
  3.         "ssession",
  4.         "test",
  5.         "ua",
  6. )
复制代码
全局级别

  • SetCommonHeaderNonCanonical
  • SetCommonHeadersNonCanonical
判定响应状态码

没啥好说的,都到这了这些应该对于各位师傅来说都是一眼就学会的基操了。

  • resp.IsSuccessState
  • resp.IsErrorState
  • resp.StatusCode
  1. // 判断响应状态码
  2. func judgeStatusCode() {
  3.     client := req.C()
  4.     resp, err := client.R().Get("http://www.baidu.com")
  5.     if err != nil {
  6.         log.Println("请求失败:", err)
  7.     }
  8.     if resp.IsSuccessState() {
  9.         fmt.Println("ok")
  10.     }
  11.     if resp.IsErrorState() {
  12.         fmt.Println("error")
  13.     }
  14.   
  15.     //可以通过响应对应的代码判断
  16.     if resp.StatusCode != http.StatusOK { //http有一个const变量,里面有很多对应的响应码,自行查看即可(文件:http\status.go)
  17.         fmt.Println("error")
  18.     }
  19.   
  20.     //打印响应体
  21.     fmt.Println(resp.Bytes())  //bytes打印
  22.     fmt.Println(resp.String()) //string打印
  23. }
复制代码
剖析数据

SetSuccessResult


  • SetSuccessResult:SetSuccessResult会⾃动剖析你给的结构体或map
  • SetErrorResult
    这里一同把SetErrorResult也讲了,可以自定义错误剖析到你自己定义的错误中去,没啥好说感觉也时,定义好了就直接给到SetErrorResult即可(详细见代码处)
运行结果如下图所示:
  1.   
  2. // 接收响应回来的json数据
  3. type user struct {
  4.     Login string `json:login`
  5.     Id    int    `json:id`
  6.     Name  string `json:name`
  7. }
  8.   
  9. // 接收错误响应
  10. type errorResp struct {
  11.     Mess string `json:message`
  12. }
  13.   
  14. // 解析响应的json数据
  15. // SetSuccessResult⾃动解析结构体或map
  16. func getHttpJson() {
  17.     client := req.C()
  18.     var respUser user
  19.     var respError errorResp
  20.     res, err := client.R().
  21.         SetSuccessResult(&respUser). //接收响应回来的json数据,同时也可以解析map
  22.         SetErrorResult(&respError).  //若请求错误将错误信息存储到该结构体中
  23.         Get("https://api.github.com/users/whoisdhan")
  24.     if err != nil {
  25.         log.Println("代码请求出错:", err)
  26.         return
  27.     }
  28.     if res.IsSuccessState() {
  29.         fmt.Println("请求成功")
  30.         fmt.Println(respUser.Login)
  31.         fmt.Println(respUser.Id)
  32.         fmt.Println(respUser.Name)
  33.     } else if res.IsErrorState() {
  34.         fmt.Println("网络请求出错:", respError.Mess)
  35.     } else {
  36.         fmt.Println("未知错误:", res.StatusCode)
  37.     }
  38.   
  39. }
复制代码
gjson


  • 字段名、.:表示读取该字段,字段名.0表示读取该键名下的数据的第一个字段,字段名.1读取第二个
  • *、?:gjson支持通配符:像在linux下令行中使用的通配符那样用就行,a*a收尾为a的都匹配
  • #:表示该字段全部元素。

    • 在结尾:字段名1.字段名2.# 表示返回字段名2的数组长度
    • 在中间,即#反面另有内容:字段名1.#.字段名2 表示返回字段名2全部元素
    • 缘故原由:这也是为啥我叫他#的意思是表示该字段全部元素,在结尾就是返回长度,不在就是返回整个数组列表

gjson剖析json数据可提取指定字段,不用定义结构体
gjson非常得当提取几个字段出来之类的,方便的一笔。
  1. // 由于我们的http请求回来的数据能方便的转为string所以也能用gjson
  2. // 模拟数据
  3. const httpjson = `
  4. {
  5.   "name":{"first":"Tom", "last": "Anderson"},
  6.   "age": 37,
  7.   "children": ["Sara", "Alex", "Jack"],
  8.   "fav.movie": "Dear Hunter",
  9.   "friends": [
  10.     {"first": "Dale", "last":"Murphy", "age": 44, "nets": ["ig", "fb", "tw"]},
  11.     {"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]},
  12.     {"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]}
  13.   ]
  14. }`
  15.   
  16. func gjsonHttp() {
  17.     //先简单用正常的httpjson数据尝试一下
  18.     client := req.C()
  19.     resp, _ := client.R().
  20.         Get("https://api.github.com/users/whoisdhan")
  21.   
  22.     login := gjson.Get(resp.String(), "login")
  23.     id := gjson.Get(resp.String(), "id")
  24.     name := gjson.Get(resp.String(), "name")
  25.     fmt.Println(login, id, name)
  26.   
  27.     //用httpjson测试数据
  28.     fmt.Println(gjson.Get(httpjson, "name.first"))
  29.     fmt.Println(gjson.Get(httpjson, "friends.#.first"))
  30.     fmt.Println(gjson.Get(httpjson, "friends.#.nets"))
  31.     fmt.Println(gjson.Get(httpjson, "fav\\.movie")) //字段存在符号的话用\\转义
  32. }
复制代码
响应数据剖析练习

这里的剖析可能有点主观了,可以按照自己的想法,只管不要被我带偏,我的不肯定是最佳的
  1. // 练习
  2. // 1. 获取⽤户信息 https://api.github.com/users/{username}
  3. // 2. 获取仓库列表信息 https://api.github.com/users/{username}/repos
  4. // 3. 用户与仓库列表信息:普通读取json、Unmarshal转结构体⽅式解析、gjson读取
  5. // 4. 用户与仓库列表信息:格式化输出到控制台
  6. // 5. 仓库列表信息保存到本地 JSON ⽂件中。
  7. //这里就固定拿仓库列表信息如下信息:
  8. // (也可以随便获取你想要的字段)
  9. //  用户信息{login、id、url、name、email}
  10. //  仓库列表信息{name、owner.login、description}
复制代码

  • myMarshalIndent:为了方便格式化,我自己写了一个格式化函数方便不同方式保存的时间进行格式化
    格式化都需要先转到map中存储才能够格式化正常的json数据出来,格式化好了就恣意你想干啥就干啥了
  • 需要注意的细节:
    有的json他是列表包裹着[],所以转的时间要注意判定用map[string]interface{}还是[]map[string]interface{}
  • json.MarshalIndent:他可以对map列表进行格式化的,由于那样也时一个正常的json数据,只不外你需要用[]map[string]interface{}列表类型进行存储(这里是一个很重要的细节,开发过程中如果不注意很容易导致崩溃)
我用了三个函数完成这个练习:

  • normalGetJson:平凡读取,就是剖析出来后整个data就直接write到文件中
  • UnmarshalToStruct:Unmarshal转结构体⽅式剖析,这里使用了上面学到的SetSuccessResult,给到结构体后进行剖析,如许也很方便
  • gjsonOutput:这里就是使用gjson了,gjson很方便,但是面对比较多字段提取的时间还是比较繁琐。
    这里复习了一个细节:map想要后续不断地赋值的话就需要进行make空间出来才行,如果是[]map的话需要给定一个空间范围,0也行,你要说明这是一个切片。如果你只是单单定义一个map变量或者map切片变量,后续是无法使用的。
    另有一个细节就是:make出来的空间是固定的,如果你要make出来的空间作为一个暂时变量赋值给其他变量的时间要注意了,用了一个空间就不要继承用了,由于你将一个空间给了多个变量的话,那么那些变量都指向你这一个空间,那么他们的值其实都一样。
运行结果:这里就放几个保存出来的文件截图

  • normalGetJson:

  • UnmarshalToStruct

  • gjsonOutput

示例代码:
  1. // 用户信息{login、id、url、name、email}
  2. // 仓库列表信息{name、owner.login、description}
  3. func gjsonOutput(username string) {
  4.     //gjson就十分简单了,只需要拿到响应json数据即可取出来看
  5.     mapUserData := make(map[string]interface{}) //用户信息存储
  6.     //仓库信息存储,
  7.     // 由于仓库是数组列表所以要给一个初始长度
  8.     // 因为可能仓库为空的,所以就初始化为0即可
  9.     mapReposData := make([]map[string]interface{}, 0)
  10.     fmt.Println("-------------------用户信息-------------------")
  11.     client := req.C()
  12.     resp, err := client.R().
  13.         SetPathParam("username", username).
  14.         Get("https://api.github.com/users/{username}")
  15.     if err != nil {
  16.         log.Println("代码请求失败:", err)
  17.     }
  18.     //gjson想要写入文件就只能转储到struct或者map中
  19.     mapUserData["login"] = gjson.Get(resp.String(), "login").String()
  20.     mapUserData["id"] = gjson.Get(resp.String(), "id").String()
  21.     mapUserData["url"] = gjson.Get(resp.String(), "url").String()
  22.     mapUserData["name"] = gjson.Get(resp.String(), "name").String()
  23.     mapUserData["email"] = gjson.Get(resp.String(), "email").String()
  24.     data, err := json.MarshalIndent(mapUserData, "", "\t")
  25.     if err != nil {
  26.         log.Println("格式化失败:", err)
  27.     }
  28.     fmt.Println(string(data))
  29.     // test := gjson.Get(resp.String(), "login")
  30.     // fmt.Println(test)
  31.   
  32.     fmt.Println("---------------------------------------------")
  33.   
  34.     fmt.Println("-------------------仓库信息-------------------")
  35.     client = req.C()
  36.     resp, err = client.R().
  37.         SetPathParam("username", username).
  38.         Get("https://api.github.com/users/{username}/repos")
  39.     if err != nil {
  40.         log.Println("代码请求失败:", err)
  41.     }
  42.     // 仓库列表信息{name、owner.login、description}
  43.     arr := gjson.Get(resp.String(), "#.name")
  44.     for i, j := range arr.Array() {
  45.         //一定要放到这里来,因为make指向同一个空间,
  46.         // 如果你在for外面定义mapTmpRepos造成取到的值会全部变成最后一个值,
  47.         // 因为同一个空间他会同步改变你map切片append里面所有的内容,
  48.         // 因为同一个空间嘛
  49.         mapTmpRepos := make(map[string]interface{})
  50.         mapTmpRepos["name"] = j.String()
  51.         mapTmpRepos["login"] = gjson.Get(resp.String(), (strconv.Itoa(i) + ".owner.login")).String()
  52.         mapTmpRepos["description"] = gjson.Get(resp.String(), (strconv.Itoa(i) + ".description")).String()
  53.         mapReposData = append(mapReposData, mapTmpRepos)
  54.     }
  55.     data, err = json.MarshalIndent(mapReposData, "", "\t")
  56.     if err != nil {
  57.         fmt.Println("格式化失败:", err)
  58.     }
  59.     fmt.Println(string(data)) //格式化的内容打印到终端
  60.   
  61.     file, err := os.OpenFile("gjson.json", os.O_CREATE|os.O_RDWR|os.O_RDWR, 0666)
  62.     if err != nil {
  63.         log.Println("打开文件失败:", err)
  64.     }
  65.     _, err = file.Write(data)
  66.     if err != nil {
  67.         log.Println("导出json失败:", err)
  68.     }
  69. }
复制代码
Cookie

请求级别:

  • SetCookies
  1. SetCookies(&http.Cookie{
  2.         Name:  "hacker",
  3.         Value: "aaa",
  4. })
复制代码
全局级别:

  • SetCommonCookies
  1. SetCommonCookies(&http.Cookie{
  2.         Name:  "Global",
  3.         Value: "dddd",
  4. })
复制代码
默认行为

就是当你请求的服务端响应了set-cookie回来后,当你再次请求的时间就会携带上这个set-cookie回来的cookie键值去请求。
禁⽤Cookie


  • SetCookieJar(nil)
存储Cookie

安装
  1. go get -u github.com/juju/persistent-cookiejar
复制代码
使用
  1. func saveCookies() {
  2.     jar, err := cookiejar.New(&cookiejar.Options{
  3.         Filename: "cookies.json",
  4.     })
  5.     if err != nil {
  6.         log.Println("保存失败")
  7.     }
  8.     defer jar.Save()
  9.     client := req.C().SetCookieJar(jar).DevMode()
  10.     client.R().Get("http://www.baidu.com")
  11. }
复制代码
证书校验

无视风险

针对一些不安全的网站请求可能会请求失败,所以需要忽略证书的校验
两种方式可以忽略:
  1. client := req.C().DevMode().EnableDumpAllWithoutResponse()
  2. //忽略证书风险
  3. //第一种
  4. //client.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
  5. //第二种
  6. client.TLSClientConfig.InsecureSkipVerify = true
  7. _, err := client.R().
  8.         Get("https://self-signed.badssl.com/")
  9. if err != nil {
  10.         fmt.Println("代码请求失败:", err)
  11. }
复制代码
配置证书

配置好风险站点的证书即可访问风险站点
证书需要访问网站的时间在欣赏器的小锁中下载即可(具体不演示了,自行百度网站证书如何下载)

  • 证书文件配置
  1. client := req.C().DevMode().EnableDumpAllWithoutResponse()
  2. //可以同时配置多个网站的证书
  3. client.SetRootCertsFromFile("cert1.crt","cert2.crt","cert3.crt")
复制代码

  • 证书内容配置
    在下载了证书之后,可以编辑证书将里面的内容配置进来也行
  1. client := req.C().DevMode().EnableDumpAllWithoutResponse()
  2. client.SetRootCertFromString("-----BEGIN CERTIFICATE-----")
复制代码
Auth身份认证


  • SetBasicAuth
  • SetDigestAuth
    区别:
    一个Basic认证,一个Digest认证
    Digest认证比较安全,请求被拦截了攻击者无法直接获取密码
    但是Basic的请求被拦截了就是直接获取到密码
    服务端支持哪一个?
    检查WWW-Authenticate响应头,返回Basic 还是 Digest就知道支持哪一个。
  1. func authHttp() {
  2.     client := req.C().DevMode().EnableDumpAllWithoutResponse()
  3.     client.R().
  4.         SetBasicAuth("username", "password").
  5.         Get("https://httpbin.org/uuid")
  6.        
  7.     client2 := req.C().DevMode().EnableDumpAllWithoutResponse()
  8.     client2.R().
  9.         SetDigestAuth("username2", "password2").
  10.         Get("https://httpbin.org/uuid")
  11. }
复制代码
文件上传下载

上传文件


  • SetFile
  • SetFiles:吸收map类型,上传多个文件
  • SetUploadCallback:表现上传进度
  1. func uploadFileHttp() {
  2.     //简单上传
  3.     client := req.C().DevMode().EnableDumpAllWithoutResponse()
  4.     callback := func(info req.UploadInfo) { //显示上传进度
  5.         fmt.Printf("\n文件名:%q\n已上传:%.2f%%\n",
  6.             info.FileName,
  7.             float64(info.UploadedSize)/float64(info.FileSize)*100.0)
  8.     }
  9.    
  10.     client.R().
  11.         //SetFile("filename", "cookies.json").
  12.         SetFiles(map[string]string{
  13.             "test":  "test.txt",
  14.             "test2": "test2.txt",
  15.             "test3": "test3.txt",
  16.         }).
  17.         SetUploadCallback(callback). //使用该函数:显示上传进度
  18.         Post("https://httpbin.org/post")
  19. }
复制代码
下载文件


  • SetOutputFile:这里是指定下载的文件路径
  • SetOutputDirectory:设置下载的默认路径,即SetOutputFile可以只给文件名,自动存在该路径下
  • SetDownloadCallback:表现下载进度
  1. func downloadFileHttp() {
  2.     client := req.C() //.DevMode().EnableDumpAllWithoutResponse()
  3.     callback := func(info req.DownloadInfo) {
  4.         if info.Response.Response != nil { //响应不为空
  5.             fmt.Printf("\n已下载:%.2f%%\n",
  6.                 float64(info.DownloadedSize)/float64(info.Response.ContentLength)*100.0)
  7.         }
  8.     }  
  9.     client.R().
  10.         //这里是指定文件路径
  11.         SetOutputFile("./baidu.html").Get("http://127.0.0.1/xxx.txt")
  12.     client2 := req.C().
  13.         //这里可以设置默认下载目录,后面直接download的时候就不用指定路径了,给文件名即可
  14.         SetOutputDirectory("./").
  15.         DevMode().
  16.         EnableDumpAllWithoutResponse()
  17.     client2.R().
  18.         SetOutputFile("baidu2.html").
  19.         SetDownloadCallback(callback).
  20.         Get("http://127.0.0.1/xxx.txt")
  21. }
复制代码
多线程下载练习


  • NewParallelDownload:创建一个多线程下载客户端
  • 其他函数在解释中标明了。
  1. func threatDownload() {
  2.     client := req.C()
  3.     err := client.NewParallelDownload("http://xxxxx.xxxx.xxx/xxx.iso").
  4.         SetConcurrency(5).               //设置 5 个线程 并行下载
  5.         SetFileMode(0777).               //设置 文件权限(可读可写可执行)。
  6.         SetOutputFile("xxx.iso").        //设定最终 存储文件名
  7.         SetSegmentSize(1024 * 1024 * 5). //每个线程下载 5MB 的数据块
  8.         SetTempRootDir("./tmp").         //这个是下载的时候指定的临时存储目录
  9.         Do()
  10.     if err != nil {
  11.         log.Println("下载失败:", err)
  12.         return
  13.     }
  14. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

立山

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表