欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

goroutine&waitgroup下載文件

0.1、索引

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ā)分段的去請求下載資源。

1、Accept-Ranges

首先下載鏈接需要在響應(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>

2、Range

假如服務(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)行劃分。

3、goroutine

我們代碼中通過獲取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&amp;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)

微信小程序開發(fā)