https://blog.waterflow.link/articles/
十余年的遂川網(wǎng)站建設(shè)經(jīng)驗(yàn),針對設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。成都全網(wǎng)營銷的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(diào)整遂川建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)建站從事“遂川網(wǎng)站設(shè)計(jì)”,“遂川網(wǎng)站推廣”以來,每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。
當(dāng)我們下載一個(gè)大文件的時(shí)候,會因?yàn)橄螺d時(shí)間太久而超時(shí)或者出錯(cuò)。那么我么我們可以利用goroutine的特性并發(fā)分段的去請求下載資源。
首先下載鏈接需要在響應(yīng)中返回Accept-Ranges,并且它的值不為 “none”,那么該服務(wù)器支持范圍請求。比如我們可以利用HEAD請求來進(jìn)行檢測
...
// head請求獲取url的header
head, err := http.Head(url)
if err != nil {
return err
}
// 判斷url是否支持指定范圍請求及哪種類型的分段請求
if head.Header.Get("Accept-Ranges") != "bytes" {
return errors.New("not support range download")
}
...
我們可以使用curl
命令看下head頭
curl -I https://agritrop.cirad.fr//1/Rapport.pdf
HTTP/1.1 200 OK
Date: Tue, 13 Sep 2022 13:52:08 GMT
Server: HTTPD
Strict-Transport-Security: max-age=
X-Content-Type-Options: nosniff
X-Frame-Options: sameorigin
Content-MD5: K4j+rsagurPwGP/5cm8k8Q==
Last-Modified: Tue, 04 Jul 2017 08:26:16 GMT
Expires: Wed, 13 Sep 2023 13:52:08 GMT
Content-Disposition: inline; filename=Rapport.pdf
Accept-Ranges: bytes # 允許范圍請求,單位是字節(jié)
Content-Length: # 文件的完整大小
Content-Type: application/pdf
X-XSS-Protection: 1; mode=block
X-Permitted-Cross-Domain-Policies: none
Cache-Control: public
其中,Accept-Ranges: bytes
表示界定范圍的單位是 bytes 。這里 Content-Length也是有效信息,因?yàn)樗峁┝宋募耐暾笮 ?/p>
假如服務(wù)器支持范圍請求的話,你可以使用 Range 首部來生成該類請求。該首部指示服務(wù)器應(yīng)該返回文件的哪一或哪幾部分。
...
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
fmt.Println("初始化request失?。?, err)
return
}
rangeL := fmt.Sprintf("bytes=%d-%d", start, end)
fmt.Println("字符范圍:", rangeL)
// 獲取制定范圍的數(shù)據(jù)
req.Header.Add("Range", rangeL)
res, err := client.Do(req)
...
單一范圍
我們可以請求資源的某一部分。這次我們依然用 cURL 來進(jìn)行測試。"-H" 選項(xiàng)可以在請求中追加一個(gè)首部行,在這個(gè)例子中,是用 Range 首部來請求圖片文件的前 1024 個(gè)字節(jié)。
curl https://agritrop.cirad.fr//1/Rapport.pdf -i -H "Range: bytes=0-1023"
HTTP/1.1 206 Partial Content
Date: Tue, 13 Sep 2022 14:00:47 GMT
Server: HTTPD
Strict-Transport-Security: max-age=
X-Content-Type-Options: nosniff
X-Frame-Options: sameorigin
Content-MD5: K4j+rsagurPwGP/5cm8k8Q==
Last-Modified: Tue, 04 Jul 2017 08:26:16 GMT
Expires: Wed, 13 Sep 2023 14:00:47 GMT
Content-Disposition: inline; filename=Rapport.pdf
Accept-Ranges: bytes
Content-Range: bytes 0-1023/ # 返回指定的字節(jié)
Content-Length: 1024
Content-Type: application/pdf
X-XSS-Protection: 1; mode=block
X-Permitted-Cross-Domain-Policies: none
Cache-Control: public
Content-Range表示請求的資源在整個(gè)資源中的位置,這個(gè)時(shí)候Content-Length就不是表示整個(gè)資源的大小,而是請求資源的大小。
多重范圍
我們也可以請求多個(gè)范圍,只需要在Range中指定多個(gè)即可
curl https://agritrop.cirad.fr//1/Rapport.pdf -i -H "Range: bytes=0-50, 100-150"
HTTP/1.1 206 Partial Content
Date: Tue, 13 Sep 2022 14:04:53 GMT
Server: HTTPD
Strict-Transport-Security: max-age=
X-Content-Type-Options: nosniff
X-Frame-Options: sameorigin
Content-MD5: K4j+rsagurPwGP/5cm8k8Q==
Last-Modified: Tue, 04 Jul 2017 08:26:16 GMT
Expires: Wed, 13 Sep 2023 14:04:53 GMT
Content-Disposition: inline; filename=Rapport.pdf
Accept-Ranges: bytes
Content-Length: 312
Content-Type: multipart/byteranges; boundary=4876db1cd4aa85af6
X-XSS-Protection: 1; mode=block
X-Permitted-Cross-Domain-Policies: none
Cache-Control: public
--4876db1cd4aa85af6
Content-type: application/pdf
Content-range: bytes 0-50/
內(nèi)容
--4876db1cd4aa85af6
Content-type: application/pdf
Content-range: bytes 100-150/
內(nèi)容
--4876db1cd4aa85af6--
服務(wù)器返回 206 Partial Content 狀態(tài)碼和 Content-Type:multipart/byteranges; boundary=3d6b6a416f9b5 頭部,Content-Type:multipart/byteranges 表示這個(gè)響應(yīng)有多個(gè) byterange。每一部分 byterange 都有他自己的 Content-type 頭部和 Content-Range,并且使用 boundary 參數(shù)對 body 進(jìn)行劃分。
我們代碼中通過獲取Contetn-Length總大小,和spPart分成了3部分,通過goroutine進(jìn)行并行的單一范圍請求。然后把最終請求的結(jié)果保存在臨時(shí)文件。之后再把這3部分內(nèi)容統(tǒng)一保存到最終的文件中
具體代碼如下:
package main
import (
"errors"
"fmt"
"io/ioutil"
"net/http"
"os"
"strconv"
"strings"
"sync"
)
// 通過Content-Length分成3部分并發(fā)執(zhí)行
var spPart = 3
// 任務(wù)編排控制
var wg sync.WaitGroup
func main() {
url := "https://agritrop.cirad.fr//1/Rapport.pdf"
err := DownloadFile(url, "rapport.pdf")
if err != nil {
panic(err)
}
}
func DownloadFile(url string, filename string) error {
if strings.TrimSpace(url) == "" {
return nil
}
// head請求獲取url的header
head, err := http.Head(url)
if err != nil {
return err
}
// 判斷url是否支持指定范圍請求及哪種類型的分段請求
if head.Header.Get("Accept-Ranges") != "bytes" {
return errors.New("not support range download")
}
contentLen, err := strconv.Atoi(head.Header.Get("Content-Length"))
if err != nil {
return err
}
offset := contentLen / spPart
for i := 0; i < spPart; i++ {
wg.Add(1)
start := offset * i
end := offset * (i + 1)
name := fmt.Sprintf("part%d", i)
go rangeDownload(url, name, start, end)
}
wg.Wait()
out, err := os.Create(filename)
if err != nil {
return err
}
defer out.Close()
for i := 0; i < spPart; i++ {
name := fmt.Sprintf("part%d", i)
file, err := ioutil.ReadFile(name)
if err != nil {
return err
}
out.WriteAt(file, int64(i*offset))
if err := os.Remove(name); err != nil {
return err
}
}
return nil
}
func rangeDownload(url string, name string, start int, end int) {
defer wg.Done()
client := http.Client{}
file, err := os.Create(name)
if err != nil {
fmt.Println("創(chuàng)建文件失?。?, err)
return
}
defer file.Close()
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
fmt.Println("初始化request失?。?, err)
return
}
rangeL := fmt.Sprintf("bytes=%d-%d", start, end)
fmt.Println("字符范圍:", rangeL)
// 獲取制定范圍的數(shù)據(jù)
req.Header.Add("Range", rangeL)
res, err := client.Do(req)
if err != nil {
fmt.Println("發(fā)起http請求失?。?, err)
return
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println("讀取返回體失敗:", err)
return
}
_, err = file.Write(body)
if err != nil {
fmt.Println("寫入文件失?。?, err)
return
}
}
網(wǎng)頁題目:goroutine&waitgroup下載文件
標(biāo)題網(wǎng)址:http://chinadenli.net/article6/dsoicog.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護(hù)、網(wǎng)站制作、外貿(mào)建站、標(biāo)簽優(yōu)化、App開發(fā)、ChatGPT
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)