0

我在 Github 上建立了一个基本项目:https ://github.com/kounelios13/range-download 。本质上,该项目尝试使用 HTTP Range 请求下载文件,将其组装起来,然后将其保存回磁盘。我正在尝试关注这篇文章(暂时除了 goroutines)。当我尝试使用范围请求下载文件时,在合并所有请求数据后,最终大小大于我将获得的原始大小并且最终文件已损坏。

这是负责下载文件的代码

type Manager struct{
    limit int
}

func NewManager(limit int) *Manager{
    return &Manager{
        limit: limit,
    }
}

func (m *Manager) DownloadBody(url string ) ([]byte ,error){
    // First we need to determine the filesize
    body := make([]byte ,0)
    response , err := http.Head(url) // We perform a Head request to get header information

    if response.StatusCode != http.StatusOK{
        return nil ,fmt.Errorf("received code %d",response.StatusCode)
    }
    if err != nil{
        return nil , err
    }

    maxConnections := m.limit // Number of maximum concurrent co routines
    bodySize , _ := strconv.Atoi(response.Header.Get("Content-Length"))
    bufferSize :=(bodySize) / (maxConnections)
    diff := bodySize % maxConnections
    read := 0
    for i:=0;i<maxConnections;i++{
        min := bufferSize * i
        max := bufferSize * (i+1)
        if i==maxConnections-1{
            max+=diff // Check to see if we have any leftover data to retrieve for the last request
        }
        req , _ := http.NewRequest("GET" , url, nil)
        req.Header.Add("Range" ,fmt.Sprintf("bytes=%d-%d",min,max))
        res , e := http.DefaultClient.Do(req)
        if e != nil{
            return body , e
        }
        log.Printf("Index:%d . Range:bytes=%d-%d",i,min,max)
        data , e :=ioutil.ReadAll(res.Body)
        res.Body.Close()
        if e != nil{
            return body,e
        }
        log.Println("Data for  request: ",len(data))
        read = read + len(data)
        body = append(body, data...)
    }
    log.Println("File size:",bodySize , "Downloaded size:",len(body)," Actual read:",read)
    return body, nil
}

我还注意到,我设置的限制越大,原始文件内容长度与所有请求主体组合的实际大小之间的差异就越大。

这是我的main.go

func main() {
    imgUrl := "https://media.wired.com/photos/5a593a7ff11e325008172bc2/16:9/w_2400,h_1350,c_limit/pulsar-831502910.jpg"
    maxConnections := 4
    manager := lib.NewManager(maxConnections)
    data , e:= manager.DownloadBody(imgUrl)
    if  e!= nil{
        log.Fatalln(e)
    }
    ioutil.WriteFile("foo.jpg" , data,0777)
}

注意:目前我对使代码并发不感兴趣。

有什么想法我可能会错过吗?

注意:我已经确认服务器使用下面的 curl 命令返回了 206 部分内容:

curl -I https://media.wired.com/photos/5a593a7ff11e325008172bc2/16:9/w_2400,h_1350,c_limit/pulsar-831502910.jpg

4

1 回答 1

1

感谢@mh-cbon,我设法编写了一个简单的测试来帮助我找到解决方案。这是固定代码

for i:=0;i<maxConnections;i++{
        min := bufferSize * i
        if i != 0{
            min++
        }
        max := bufferSize * (i+1)
        if i==maxConnections-1{
            max+=diff // Check to see if we have any leftover data to retrieve for the last request
        }
        req , _ := http.NewRequest("GET" , url, nil)
        req.Header.Add("Range" ,fmt.Sprintf("bytes=%d-%d",min,max))
        res , e := http.DefaultClient.Do(req)
        if e != nil{
            return body , e
        }
        log.Printf("Index:%d . Range:bytes=%d-%d",i,min,max)
        data , e :=ioutil.ReadAll(res.Body)
        res.Body.Close()
        if e != nil{
            return body,e
        }
        log.Println("Data for  request: ",len(data))
        read = read + len(data)
        body = append(body, data...)
    }

问题是我没有正确的最小值以 . 所以可以说我有以下范围可供下载:

  • 0-100
  • 101 - 200

我的代码将下载字节0-100然后再从而100-200不是101-200

所以我确保在每次迭代(第一次除外)中将 min 增加 1,以免与之前的范围重叠

这是我设法从作为注释提供的文档中修复的一个简单测试:

func TestManager_DownloadBody(t *testing.T) {
    ts := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {

        http.ServeContent(writer,request ,"hey" ,time.Now() ,bytes.NewReader([]byte(`hello world!!!!`)))
    }))

    defer ts.Close()


    m := NewManager(4)
    data , err := m.DownloadBody(ts.URL)
    if err != nil{
        t.Errorf("%s",err)
    }

    if string(data) != "hello world!!!!"{
        t.Errorf("Expected hello world!!!! . received : [%s]",data)
    }
}

当然还有更多的测试要写,但这是一个好的开始

于 2020-12-14T07:43:00.133 回答