直接上代码
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
}
网友评论