golang http range头,部分请求资源

2023-02-13  本文已影响0人  哆啦在这A梦在哪

直接上代码

package main

import (
    "errors"
    "io"
    "log"
    "net/http"
    "os"
    "strconv"
    "time"
)

func main() {
    i := 0
    fileURL := "http://127.0.0.1:8080/assets/aa.jpeg" // 你的资源地址
    fileLen, err := getFileLength(fileURL)// 获取一下资源大小
    if err != nil {
        log.Println(err)
        return
    }
    log.Println("filelen:", fileLen)
    f, err := os.OpenFile("aa", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
    if err != nil {
        log.Println(err)
        return
    }
    defer f.Close()

    for {
        da, err := get(i, fileLen, fileURL)
        if err != nil || len(da) == 0 {
            log.Println(err)
            return
        }
        if _, err := f.Write(da); err != nil {
            log.Println(err)
            return
        }
        i += 20000
        time.Sleep(time.Second)
    }

}

func get(flag int, fileLen int64, fileURL string) ([]byte, error) {
    client := &http.Client{}
    req, err := http.NewRequest("GET", fileURL, nil)
    if err != nil {
        return nil, err
    }
    // Range 的内容参数就只有一个 bytes
    // 中间用减号隔开,不写头或者尾,代表从头或到结尾,比如:bytes= -200,就是从头到两百
    // 可以支持多个,用逗号隔开,比如 bytes=0-200,600-900
    // 注意区间两边都能获取到
    rangeBytes := ""
    switch {
    case int64(flag)+20000 >= fileLen:
        // 注意这一步,如果超过范围,会导致当前这次失败
        // 比如我这里每次取 20000,但是最后剩下 200,这次就反馈 416,不会反馈剩余的这 200 数据,就会丢数据
        rangeBytes = "bytes=" + strconv.Itoa(flag+1) + "-"
    case flag == 0:
        rangeBytes = "bytes=" + strconv.Itoa(flag) + "-" + strconv.Itoa(flag+20000)
    default:
        rangeBytes = "bytes=" + strconv.Itoa(flag+1) + "-" + strconv.Itoa(flag+20000)
    }
    log.Println("rangeBytes:", rangeBytes)
    req.Header.Add("Range", rangeBytes)
    resp, err := client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    da, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }
    log.Println("code:", resp.StatusCode, "flag:", flag, "/:", fileLen)
    if resp.StatusCode != 206 {
        log.Println("stop:", string(da))
        return nil, errors.New(string(da))
    }
    return da, nil
}

func getFileLength(url string) (int64, error) {
    req, err := http.Head(url)
    return req.ContentLength, err
}

上一篇 下一篇

猜你喜欢

热点阅读