Go红队开发—web网络编程

news2025/3/13 13:11:03

文章目录

  • web网络编程
    • Req
      • 快速请求
    • 调试
      • DevMode
      • DebugLog
      • TraceInfo瓶颈分析
    • 控制请求与响应
      • 控制请求的字段内容
      • 控制调试打印的内容
      • 分开dump请求与响应部分
      • 请求体设置
    • 作用范围级别
      • 设置参数查询
      • URL 路径参数
      • 表单请求设置
      • 请求头设置
    • 判断响应状态码
    • 解析数据
      • SetSuccessResult
      • gjson
      • 响应数据解析练习
    • Cookie
      • 默认行为
      • 禁⽤Cookie
      • 存储Cookie
    • 证书校验
      • 无视风险
      • 配置证书
    • Auth身份认证
    • 文件上传下载
      • 上传文件
      • 下载文件
      • 多线程下载练习

web网络编程

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

Req

简单的请求

  • 客户端创建
  • 请求设置

func reqHttp() {

    client := req.C()       //客户端创建

    res, err := client.R(). //请求设置,这个点的意思链式调用,后续在控制请求中会讲

                Get("https://httpbin.org/uuid")

    if err != nil {

        log.Println("请求失败:", err)

    }

    fmt.Println(res)

}

快速请求

  • MustGet
    测试使用可以,正式开发不建议使用,可控性差

// 快速使用,一般用在test的时候

func testHttp() {

  

    resp := req.MustGet("https://httpbin.org/uuid") //这里就是发起了一次请求

    fmt.Println(resp.String())                      //第一种打印*req.Response类型的响应体

    fmt.Println(string(resp.Bytes()))               //第二种打印*req.Response类型的响应体

}

调试

DevMode

DevMode是直接开启全局调试,自动打印出来

// 调试模式

func devModeReq() {

    //使用req进行请求,所以req的调试模式也是在req启动

    req.DevMode()                                   //开启调试模式,就会打印出来请求的过程以及响应内容

    req.SetCommonBasicAuth("username", "password"). //设置用户名和密码

                            SetTimeout(5 * time.Second). //设置超时时间

                            SetUserAgent("my-ua")

    resp := req.MustGet("https://httpbin.org/uuid")

    //没有开启调试模式但是想打印的话就正常打印

    fmt.Println(resp.String())        //第一种打印*req.Response类型的响应体

    fmt.Println(string(resp.Bytes())) //第二种打印*req.Response类型的响应体

}

DebugLog

DebugLog 是跟踪请求的过程

他可以看到你整个请求的过程,重定向的信息等等

// 查看请求的过程发生了什么

func deLog() {

    client := req.C().

        EnableDebugLog() //开启DebugLog

    client.R().Get("http://baidu.com/s?wd=req")

}

TraceInfo瓶颈分析

trace跟踪信息

func traceReq() {

    // Enable trace at request level

    client := req.C()

    resp, err := client.R().

        EnableTrace(). //开启瓶颈分析

        Get("https://api.github.com/users/imroc")

    if err != nil {

        log.Fatal(err)

    }

    trace := resp.TraceInfo()  //trace跟踪信息

    fmt.Println(trace.Blame()) //分析总结(请求减慢的原因归咎)

  

    fmt.Println(trace) // 打印内容

}

控制请求与响应

控制请求的字段内容

这里做一个了解,后面会详细说一下作用范围,这里就过一遍即可,知道哪些字段可控(其实都可控)

func controlReq() {

  

    client := req.C().

        SetUserAgent("my-ua"). //设置ua头,在client中设置,在下面的R()中设置不了

        //EnableDumpAllToFile("log.txt") //将请求的信息写到该文件中

        //捕获请求和响应,

        // 想要看的更加详细就可以开启dump所有内容,
        // 就能够看到我们是不是真的改变了请求内容

        EnableDumpAll()

  

    parms := map[string]string{

        "a": "123",

        "b": "hello",

    }

  

    resp, err := client.R(). //拿到请求体

                    SetPathParam("usernamae", "imroc"). //设置请求路径,用username作为占位符

                    SetPathParam("xxx", "test").        //再次设置,用xxx作为占位符

                    SetQueryParam("a", "12").           //设置请求参数,a=12

                    SetQueryParams(parms).              //用map来作为请求参数,用于多个参数的时候

                    SetHeader("mycookie", "test").      //设置请求头

                    SetHeader("mysession", "test2").    //设置请求头

                    SetBody("body=world").              //设置请求体

                    Get("https://httpbin.org/uuid")

  

    //以上设置暂时在初期阶段够用了。

    if err != nil {

        log.Println("请求出错:", err)

    }

    fmt.Println(resp)

}

控制调试打印的内容

  • SetCommonDumpOptions:控制输出的内容
  • EnableDumpAllToFile:dump到文件中

输出的log2.txt文件内容如下

// 控制调试打印的内容

// 全局应用

func controlDevOptions() {

    client := req.C()

    opt := &req.DumpOptions{
        Output:         os.Stdout, //标准输出
        RequestHeader:  false,     //不输出请求头
        RequestBody:    false,     //不输出请求体
        ResponseHeader: true,      //输出响应头
        ResponseBody:   true,      //输出响应体
        Async:          false,     //不进行异步输出

    }
    client.SetCommonDumpOptions(opt).
        EnableDumpAllToFile("log2.txt")
    client.R().Get("https://httpbin.org/uuid")

}

分开dump请求与响应部分

  • var bufReq, bufResp bytes.Buffer:需要用变量来接收请求与响应不同部分
  • SetDumpOptions:控制dump导出部分
// 分别打印请求与响应部分

// 在R中控制调试打印的内容,只作用与本次R请求,与上面的client直接全局设置的不同

func controlReqRespOutPut() {

    client := req.C()

    var bufReq, bufResp bytes.Buffer

    client.R().

        // 不开启的话就会导致无法转储出去单独打印请求体响应体

        EnableDump(). //EnableDump启用转储,包括请求和响应的所有内容。

        SetDumpOptions(&req.DumpOptions{

            RequestOutput:  &bufReq,  //将请求体输出到这里

            ResponseOutput: &bufResp, //将响应体输出到这里

            RequestHeader:  true,

            RequestBody:    true,

            ResponseHeader: true,

            ResponseBody:   true,

        }).

        SetBody("body=hello+world!").

        Get("https://httpbin.org/uuid")

  

    fmt.Println("请求体")

    fmt.Println(bufReq.String())

    fmt.Println("响应体")

    fmt.Println(bufResp.String())

}

请求体设置

SetBody 可以接受任意类型

PS: EnableDumpAllWithoutResponse因为开启了调试模式,所以会打印很多东西,但是可以忽略响应打印出来结果,所以这函数就是忽略响应结果,只看请求。

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

400

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

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

以下是代码:

// 设置请求体中的一些骚姿势

func setbodyHttp() {

    type test struct {

        Name string

        Age  int

    }

    t := test{

        Name: "zhangsan",

        Age:  123,

    }

    client := req.C().DevMode().EnableDumpAllWithoutResponse()

    client.R().

        SetBody(t).

        SetContentType("application/xml").

        Get("https://httpbin.org/uuid")

  

    client2 := req.C().DevMode().EnableDumpAllWithoutResponse()

    client2.R().

        SetBodyXmlMarshal(t).

        Get("https://httpbin.org/uuid")

  

}

作用范围级别

在设置请求参数的时候,有分两种作用范围设置,一种全局(客户端级别),另一种就是只作用与这一个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不是我定义的,拿来就用即可。
client3 := req.C().DevMode().EnableDumpAllWithoutResponse()

v := url.Values{
	"p": []string{"hello", "world", "!"},
}
client3.R().
	SetFormDataFromValues(v).
	Post("https://httpbin.org/post")

  • multipart ⽅式提交表单:EnableForceMultipart
client3 := req.C().DevMode().EnableDumpAllWithoutResponse()
v := url.Values{
	"p": []string{"hello", "world", "!"},
}
client3.R().
	EnableForceMultipart().
	SetFormDataFromValues(v).
	Post("https://httpbin.org/post")


全局级别:

  • SetCommonFormData
  • SetCommonFormDataFromValues

请求头设置

请求级别:

  • SetHeader:自动将你传进的header键的首字母大写
  • SetHeaders:接收map类型,自动将你传进的header键的首字母大写
  • SetHeaderNonCanonical:你给什么样就输出什么样,不会自动给你首字母大写
  • SetHeadersNonCanonical:你给什么样就输出什么样,不会自动给你首字母大写
  • SetHeaderOrder:控制header的顺序,因为有的服务端可能会对header的顺序判断是否允许请求,设置了SetHeaderOrder,他就会按照你给定的顺序进行排序请求过去。
request.SetHeaderOrder( 
	"cookie", 
	"ssession", 
	"test",
	"ua", 
)

全局级别

  • SetCommonHeaderNonCanonical
  • SetCommonHeadersNonCanonical

判断响应状态码

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

  • resp.IsSuccessState
  • resp.IsErrorState
  • resp.StatusCode
// 判断响应状态码

func judgeStatusCode() {

    client := req.C()

    resp, err := client.R().Get("http://www.baidu.com")

    if err != nil {

        log.Println("请求失败:", err)

    }

    if resp.IsSuccessState() {

        fmt.Println("ok")

    }

    if resp.IsErrorState() {

        fmt.Println("error")

    }

  

    //可以通过响应对应的代码判断

    if resp.StatusCode != http.StatusOK { //http有一个const变量,里面有很多对应的响应码,自行查看即可(文件:http\status.go)

        fmt.Println("error")

    }

  

    //打印响应体

    fmt.Println(resp.Bytes())  //bytes打印

    fmt.Println(resp.String()) //string打印

}

解析数据

SetSuccessResult

  • SetSuccessResult:SetSuccessResult会⾃动解析你给的结构体或map

  • SetErrorResult
    这里一同把SetErrorResult也讲了,可以自定义错误解析到你自己定义的错误中去,没啥好说感觉也时,定义好了就直接给到SetErrorResult即可(详细见代码处)

运行结果如下图所示:

  

// 接收响应回来的json数据

type user struct {

    Login string `json:login`

    Id    int    `json:id`

    Name  string `json:name`

}

  

// 接收错误响应

type errorResp struct {

    Mess string `json:message`

}

  

// 解析响应的json数据

// SetSuccessResult⾃动解析结构体或map

func getHttpJson() {

    client := req.C()

    var respUser user

    var respError errorResp

    res, err := client.R().

        SetSuccessResult(&respUser). //接收响应回来的json数据,同时也可以解析map

        SetErrorResult(&respError).  //若请求错误将错误信息存储到该结构体中

        Get("https://api.github.com/users/whoisdhan")

    if err != nil {

        log.Println("代码请求出错:", err)

        return

    }

    if res.IsSuccessState() {

        fmt.Println("请求成功")

        fmt.Println(respUser.Login)

        fmt.Println(respUser.Id)

        fmt.Println(respUser.Name)

    } else if res.IsErrorState() {

        fmt.Println("网络请求出错:", respError.Mess)

    } else {

        fmt.Println("未知错误:", res.StatusCode)

    }

  

}

gjson

  • 字段名.:表示读取该字段,字段名.0表示读取该键名下的数据的第一个字段,字段名.1读取第二个
  • *?:gjson支持通配符:像在linux命令行中使用的通配符那样用就行,a*a收尾为a的都匹配
  • #:表示该字段所有元素。
    • 在结尾:字段名1.字段名2.# 表示返回字段名2的数组长度
    • 在中间,即#后面还有内容:字段名1.#.字段名2 表示返回字段名2所有元素
    • 原因:这也是为啥我叫他#的意思是表示该字段所有元素,在结尾就是返回长度,不在就是返回整个数组列表

gjson解析json数据可提取指定字段,不用定义结构体

gjson非常适合提取几个字段出来之类的,方便的一笔。

// 由于我们的http请求回来的数据能方便的转为string所以也能用gjson

// 模拟数据

const httpjson = `

{

  "name":{"first":"Tom", "last": "Anderson"},

  "age": 37,

  "children": ["Sara", "Alex", "Jack"],

  "fav.movie": "Dear Hunter",

  "friends": [

    {"first": "Dale", "last":"Murphy", "age": 44, "nets": ["ig", "fb", "tw"]},

    {"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]},

    {"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]}

  ]

}`

  

func gjsonHttp() {

    //先简单用正常的httpjson数据尝试一下

    client := req.C()

    resp, _ := client.R().

        Get("https://api.github.com/users/whoisdhan")

  

    login := gjson.Get(resp.String(), "login")

    id := gjson.Get(resp.String(), "id")

    name := gjson.Get(resp.String(), "name")

    fmt.Println(login, id, name)

  

    //用httpjson测试数据

    fmt.Println(gjson.Get(httpjson, "name.first"))

    fmt.Println(gjson.Get(httpjson, "friends.#.first"))

    fmt.Println(gjson.Get(httpjson, "friends.#.nets"))

    fmt.Println(gjson.Get(httpjson, "fav\\.movie")) //字段存在符号的话用\\转义

}

响应数据解析练习

这里的解析可能有点主观了,可以按照自己的想法,尽量不要被我带偏,我的不一定是最佳的

// 练习
// 1. 获取⽤户信息 https://api.github.com/users/{username}
// 2. 获取仓库列表信息 https://api.github.com/users/{username}/repos
// 3. 用户与仓库列表信息:普通读取json、Unmarshal转结构体⽅式解析、gjson读取
// 4. 用户与仓库列表信息:格式化输出到控制台
// 5. 仓库列表信息保存到本地 JSON ⽂件中。
//这里就固定拿仓库列表信息如下信息:
// (也可以随便获取你想要的字段)
//  用户信息{login、id、url、name、email}
//  仓库列表信息{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

示例代码:

// 用户信息{login、id、url、name、email}

// 仓库列表信息{name、owner.login、description}

func gjsonOutput(username string) {

    //gjson就十分简单了,只需要拿到响应json数据即可取出来看

    mapUserData := make(map[string]interface{}) //用户信息存储

    //仓库信息存储,

    // 由于仓库是数组列表所以要给一个初始长度

    // 因为可能仓库为空的,所以就初始化为0即可

    mapReposData := make([]map[string]interface{}, 0)

    fmt.Println("-------------------用户信息-------------------")

    client := req.C()

    resp, err := client.R().

        SetPathParam("username", username).

        Get("https://api.github.com/users/{username}")

    if err != nil {

        log.Println("代码请求失败:", err)

    }

    //gjson想要写入文件就只能转储到struct或者map中

    mapUserData["login"] = gjson.Get(resp.String(), "login").String()

    mapUserData["id"] = gjson.Get(resp.String(), "id").String()

    mapUserData["url"] = gjson.Get(resp.String(), "url").String()

    mapUserData["name"] = gjson.Get(resp.String(), "name").String()

    mapUserData["email"] = gjson.Get(resp.String(), "email").String()

    data, err := json.MarshalIndent(mapUserData, "", "\t")

    if err != nil {

        log.Println("格式化失败:", err)

    }

    fmt.Println(string(data))

    // test := gjson.Get(resp.String(), "login")

    // fmt.Println(test)

  

    fmt.Println("---------------------------------------------")

  

    fmt.Println("-------------------仓库信息-------------------")

    client = req.C()

    resp, err = client.R().

        SetPathParam("username", username).

        Get("https://api.github.com/users/{username}/repos")

    if err != nil {

        log.Println("代码请求失败:", err)

    }

    // 仓库列表信息{name、owner.login、description}

    arr := gjson.Get(resp.String(), "#.name")

    for i, j := range arr.Array() {

        //一定要放到这里来,因为make指向同一个空间,

        // 如果你在for外面定义mapTmpRepos造成取到的值会全部变成最后一个值,

        // 因为同一个空间他会同步改变你map切片append里面所有的内容,

        // 因为同一个空间嘛

        mapTmpRepos := make(map[string]interface{})

        mapTmpRepos["name"] = j.String()

        mapTmpRepos["login"] = gjson.Get(resp.String(), (strconv.Itoa(i) + ".owner.login")).String()

        mapTmpRepos["description"] = gjson.Get(resp.String(), (strconv.Itoa(i) + ".description")).String()

        mapReposData = append(mapReposData, mapTmpRepos)

    }

    data, err = json.MarshalIndent(mapReposData, "", "\t")

    if err != nil {

        fmt.Println("格式化失败:", err)

    }

    fmt.Println(string(data)) //格式化的内容打印到终端

  

    file, err := os.OpenFile("gjson.json", os.O_CREATE|os.O_RDWR|os.O_RDWR, 0666)

    if err != nil {

        log.Println("打开文件失败:", err)

    }

    _, err = file.Write(data)

    if err != nil {

        log.Println("导出json失败:", err)

    }

}

Cookie

请求级别:

  • SetCookies
SetCookies(&http.Cookie{
	Name:  "hacker",
	Value: "aaa",
})

全局级别:

  • SetCommonCookies
SetCommonCookies(&http.Cookie{
	Name:  "Global",
	Value: "dddd",
})

默认行为

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

禁⽤Cookie

  • SetCookieJar(nil)

存储Cookie

安装

go get -u github.com/juju/persistent-cookiejar

使用

func saveCookies() {
    jar, err := cookiejar.New(&cookiejar.Options{
        Filename: "cookies.json",
    })

    if err != nil {
        log.Println("保存失败")
    }

    defer jar.Save()
    client := req.C().SetCookieJar(jar).DevMode()
    client.R().Get("http://www.baidu.com")

}

证书校验

无视风险

针对一些不安全的网站请求可能会请求失败,所以需要忽略证书的校验

两种方式可以忽略:

client := req.C().DevMode().EnableDumpAllWithoutResponse()
//忽略证书风险
//第一种
//client.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
//第二种
client.TLSClientConfig.InsecureSkipVerify = true
_, err := client.R().
	Get("https://self-signed.badssl.com/")
if err != nil {
	fmt.Println("代码请求失败:", err)
}

配置证书

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

  • 证书文件配置
client := req.C().DevMode().EnableDumpAllWithoutResponse()
//可以同时配置多个网站的证书
client.SetRootCertsFromFile("cert1.crt","cert2.crt","cert3.crt")
  • 证书内容配置
    在下载了证书之后,可以编辑证书将里面的内容配置进来也行
client := req.C().DevMode().EnableDumpAllWithoutResponse()
client.SetRootCertFromString("-----BEGIN CERTIFICATE-----")

Auth身份认证

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

        Get("https://httpbin.org/uuid")

}

文件上传下载

上传文件

  • SetFile
  • SetFiles:接收map类型,上传多个文件
  • SetUploadCallback:显示上传进度
func uploadFileHttp() {
    //简单上传
    client := req.C().DevMode().EnableDumpAllWithoutResponse()

    callback := func(info req.UploadInfo) { //显示上传进度

        fmt.Printf("\n文件名:%q\n已上传:%.2f%%\n",
            info.FileName,
            float64(info.UploadedSize)/float64(info.FileSize)*100.0)
    }
    
    client.R().
        //SetFile("filename", "cookies.json").
        SetFiles(map[string]string{

            "test":  "test.txt",

            "test2": "test2.txt",

            "test3": "test3.txt",

        }).
        SetUploadCallback(callback). //使用该函数:显示上传进度
        Post("https://httpbin.org/post")

}

下载文件

  • SetOutputFile:这里是指定下载的文件路径
  • SetOutputDirectory:设置下载的默认路径,即SetOutputFile可以只给文件名,自动存在该路径下
  • SetDownloadCallback:显示下载进度
func downloadFileHttp() {

    client := req.C() //.DevMode().EnableDumpAllWithoutResponse()

    callback := func(info req.DownloadInfo) {

        if info.Response.Response != nil { //响应不为空

            fmt.Printf("\n已下载:%.2f%%\n",

                float64(info.DownloadedSize)/float64(info.Response.ContentLength)*100.0)

        }

    }  

    client.R().

        //这里是指定文件路径

        SetOutputFile("./baidu.html").Get("http://127.0.0.1/xxx.txt")

    client2 := req.C().

        //这里可以设置默认下载目录,后面直接download的时候就不用指定路径了,给文件名即可

        SetOutputDirectory("./").

        DevMode().

        EnableDumpAllWithoutResponse()

    client2.R().

        SetOutputFile("baidu2.html").

        SetDownloadCallback(callback).

        Get("http://127.0.0.1/xxx.txt")

}

多线程下载练习

  • NewParallelDownload:创建一个多线程下载客户端
  • 其他函数在注释中标明了。
func threatDownload() {

    client := req.C()

    err := client.NewParallelDownload("http://xxxxx.xxxx.xxx/xxx.iso").

        SetConcurrency(5).               //设置 5 个线程 并行下载

        SetFileMode(0777).               //设置 文件权限(可读可写可执行)。

        SetOutputFile("xxx.iso").        //设定最终 存储文件名

        SetSegmentSize(1024 * 1024 * 5). //每个线程下载 5MB 的数据块

        SetTempRootDir("./tmp").         //这个是下载的时候指定的临时存储目录

        Do()

    if err != nil {

        log.Println("下载失败:", err)

        return

    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2314312.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

轻量级模块化前端框架:快速构建强大的Web界面

轻量级模块化前端框架:快速构建强大的Web界面 在当今快节奏的Web开发环境中,选择一个高效且灵活的前端框架至关重要。UIkit 是一个轻量级的模块化前端框架,旨在帮助开发者快速构建功能强大且响应迅速的Web界面。 UIkit提供了丰富的组件和工…

qt+opengl 播放yuv视频

一、实现效果 二、pro文件 Qt widgets opengl 三、主要代码 #include "glwidget.h"GLWidget::GLWidget(QWidget *parent) : QOpenGLWidget(parent) {connect(&m_timer, &QTimer::timeout, this,[&](){this->update();});m_timer.start(1000/33); }v…

5G基本概念

作者:私语茶馆 1. 5G应用场景概述 1.1.5G应用场景 ITU域2015年定义了三大应用场景:eMBB(增强型移动宽带)、uRLLC(低时延高可靠通信)、mMTC(海量物联网通信); emBB:Enhanced Mobile Broadband ,移动互联网应用,是4G MBB(移动宽带)的升级,主要侧重于网络速率、带…

PH热榜 | 2025-03-12

1. Fluently 标语:开始说英语,就像说你的母语一样流利。 介绍:想象一下,有一个像人类一样的英语教练,全天候在线、价格却便宜15倍。这就是 Fluently 🚀 纠正你的错误,提升你的词汇量、发音和语…

Python Web项目的服务器部署

一.部署运行 1.虚拟环境的安装:(一行一行运行) wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh bash miniconda.sh -b -p /opt/miniconda3 echo export PATH"/opt/miniconda3/bin:$PAT…

[项目]基于FreeRTOS的STM32四轴飞行器: 八.遥控器摇杆

基于FreeRTOS的STM32四轴飞行器: 八.遥控器摇杆 一.摇杆数据的扫描二.处理摇杆数据三.微调按键处理 一.摇杆数据的扫描 下面摇杆初始化时,启动了ADC-DMA进行了采集,已经开始转换直接将数据通过DMA存入buff数组中: static uint16_t buff[4] …

附下载 | 2024 OWASP Top 10 基础设施安全风险.pdf

《2024 OWASP Top 10 基础设施安全风险》报告,由OWASP(开放网络应用安全项目)发布,旨在提升企业和组织对基础设施安全风险、威胁与漏洞的意识,并提供高质量的信息和最佳实践建议。报告列出了2024年最重要的10大基础设施…

Pytorch的一小步,昇腾芯片的一大步

Pytorch的一小步,昇腾芯片的一大步 相信在AI圈的人多多少少都看到了最近的信息:PyTorch最新2.1版本宣布支持华为昇腾芯片! 1、 发生了什么事儿? 在2023年10月4日PyTorch 2.1版本的发布博客上,PyTorch介绍的beta版本…

化工厂防爆气象站:为石油化工、天然气等领域提供安全保障

【TH-FB02】在石油化工、天然气等高危行业中,安全生产是至关重要的。这些行业常常面临着易燃易爆、有毒有害等潜在风险,因此,对气象条件的监测和预警显得尤为重要。化工厂防爆气象站作为一种专门设计用于这些特殊环境的气象监测设备&#xff…

《A Gentle Introduction to Graph Neural Networks》-GNN的综述性论文

目录 一、什么数据可以表示成一张图 (1)什么是图? (2)如何表示图的属性 (3)images as graphs(将图片表示为图) (4)text as graphs&#xff08…

[023-01-40].第40节:组件应用 - OpenFeign与 Sentinel 集成实现fallback服务降级

SpringCloud学习大纲 一、需求说明: 需求1:通过fallback属性进行统一配置 a.问题分析: 1.需要实现cloudalibaba-consumer-nacos-order83模块通过OpenFeign调用cloudalibaba-provider-payment9001 83服务通过OpenFeign调用 9001微服务&…

设计模式-结构型模式-装饰器模式

概述 装饰器模式 : Decorator Pattern : 是一种结构型设计模式. 作用 : 允许你动态地给对象添加功能或职责,而无需修改其原始类的代码,非常的符合 开闭原则。 实现思路 :通过创建一个包装对象(即装饰器),来…

visual studio配置opencv

文章目录 step1 下载opencvstep2 配置包含目录step 3 配置链接器step4 配置环境变量并重启vs2022step5 检查代码 step1 下载opencv 下载 opencv-4.8.0-windows.exe https://cloud.189.cn/web/share?codefUnqEb7naUra step2 配置包含目录 step 3 配置链接器 step4 配置环境变…

docker修改daemon.json文件后无法启动

1.问题描述 使用阿里云docker镜像安装的docker,安装成功后默认可以启动。但是修改daemon.json配置后docker服务无法启动,提示如下错误: 从上图发现,docker服务默认使用阿里docker镜像仓库 2.解决方法 根据提示找到docker服务目…

Linux网络:网络与操作系统1

本文是介绍网络的基本结构,以及和OS之间有什么关系 OSI七层模型 引入 使用网络是为了解决信息的长距离传送,那就需要解决四个问题: 接收方如何使用数据传输的可靠性主机如何定位数据包在局域网如何转发 人们选择用网络协议(t…

姚安娜新剧瘦了一圈,《仁心俱乐部》急诊医生顾诗宜在线上岗

《仁心俱乐部》在芒果 TV 播出,湖南卫视金鹰独播剧场也随之播出,这一剧集受到了不少观众的关注。姚安娜在剧中饰演的急诊科医生顾诗宜,她为患者检查身体时动作娴熟,与患者沟通时展现出的耐心和专注,都展现出很高的专业…

串口数据记录仪DIY,体积小,全开源

作用 产品到客户现场出现异常情况,这个时候就需要一个日志记录仪、黑匣子,可以记录产品的工作情况,当出现异常时,可以搜集到上下文的数据,从而判断问题原因。 之前从网上买过,但是出现过丢数据的情况耽误…

51单片机Proteus仿真速成教程——P1-软件与配置+Proteus绘制51单片机最小系统+新建程序模版

前言:本文主要围绕 51 单片机最小系统的绘制及程序模板创建展开。首先介绍了使用 Proteus 绘制 51 单片机最小系统的详细步骤,包括软件安装获取途径、工程创建、器件添加(如单片机 AT89C51、晶振、电容、电阻、按键等)、外围电路&…

使用 pytesseract 进行 OCR 识别:以固定区域经纬度提取为例

引言 在智能交通、地图定位等应用场景中,经常会遇到需要从图像中提取经纬度信息的需求。本篇文章将介绍如何利用 Python 的 pytesseract 库结合 PIL 对图像进行预处理,通过固定区域裁剪,来有效地识别出图像上显示的经纬度信息。 1. OCR 与 …

【51单片机】程序实验15.DS18B20温度传感器

主要参考学习资料:B站【普中官方】51单片机手把手教学视频 开发资料下载链接:http://www.prechin.cn/gongsixinwen/208.html 单片机套装:普中STC51单片机开发板A4标准版套餐7 目录 DS18B20介绍主要特性内部结构控制时序初始化时序写时序读时序…