Golang中HTTP状态码206的详解与应用场景

Golang中HTTP状态码206的详解与应用场景 有人使用过HTTP的206状态码吗?

7 回复

哦,当然。

更多关于Golang中HTTP状态码206的详解与应用场景的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


如何?何时?何地?

在为范围请求提供部分内容时?

哪种类型的内容? 你如何定义一个范围? 你能告诉我你在什么情况下使用过它吗?

谢谢,你曾经用它处理过图片或视频吗?

MDN Web Docs

MDN Web Docs

MDN Web Docs

HTTP 范围请求

HTTP 范围请求允许服务器仅向客户端发送 HTTP 消息的一部分。部分请求对于大型媒体或具有暂停和恢复功能的文件下载非常有用。

HTTP 206状态码(Partial Content)是HTTP协议中用于分块传输的重要状态码。当客户端通过Range头请求部分资源时,服务器会返回206状态码及请求的范围数据。

核心特性

  • 支持断点续传和并行下载
  • 必须包含Content-Range响应头
  • 可同时传输多个范围(multipart/byteranges)

Go语言实现示例

1. 服务器端实现

package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
    "strconv"
    "strings"
)

func servePartialContent(w http.ResponseWriter, r *http.Request) {
    filePath := "largefile.zip"
    file, err := os.Open(filePath)
    if err != nil {
        http.Error(w, "File not found", http.StatusNotFound)
        return
    }
    defer file.Close()

    fileInfo, _ := file.Stat()
    fileSize := fileInfo.Size()

    // 解析Range头
    rangeHeader := r.Header.Get("Range")
    if rangeHeader == "" {
        // 没有Range头,返回完整文件
        w.Header().Set("Content-Length", strconv.FormatInt(fileSize, 10))
        io.Copy(w, file)
        return
    }

    // 解析范围请求
    ranges := strings.Replace(rangeHeader, "bytes=", "", 1)
    rangeParts := strings.Split(ranges, "-")
    
    start, _ := strconv.ParseInt(rangeParts[0], 10, 64)
    var end int64
    if rangeParts[1] == "" {
        end = fileSize - 1
    } else {
        end, _ = strconv.ParseInt(rangeParts[1], 10, 64)
    }

    // 验证范围有效性
    if start >= fileSize || end >= fileSize || start > end {
        http.Error(w, "Requested range not satisfiable", http.StatusRequestedRangeNotSatisfiable)
        return
    }

    // 设置响应头
    w.Header().Set("Content-Range", 
        fmt.Sprintf("bytes %d-%d/%d", start, end, fileSize))
    w.Header().Set("Accept-Ranges", "bytes")
    w.Header().Set("Content-Length", strconv.FormatInt(end-start+1, 10))
    w.WriteHeader(http.StatusPartialContent)

    // 发送部分内容
    file.Seek(start, 0)
    io.CopyN(w, file, end-start+1)
}

func main() {
    http.HandleFunc("/download", servePartialContent)
    http.ListenAndServe(":8080", nil)
}

2. 客户端请求示例

package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
    "strconv"
)

func downloadPartial(url string, start, end int64, filename string) error {
    client := &http.Client{}
    
    req, _ := http.NewRequest("GET", url, nil)
    rangeHeader := fmt.Sprintf("bytes=%d-%d", start, end)
    req.Header.Set("Range", rangeHeader)

    resp, err := client.Do(req)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    if resp.StatusCode != http.StatusPartialContent {
        return fmt.Errorf("unexpected status: %d", resp.StatusCode)
    }

    // 读取Content-Range头
    contentRange := resp.Header.Get("Content-Range")
    fmt.Printf("Downloading range: %s\n", contentRange)

    // 保存部分文件
    file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        return err
    }
    defer file.Close()

    file.Seek(start, 0)
    _, err = io.Copy(file, resp.Body)
    return err
}

func main() {
    // 并行下载示例
    url := "http://localhost:8080/download"
    totalSize := int64(1024 * 1024 * 100) // 100MB
    
    // 分4个部分下载
    chunkSize := totalSize / 4
    for i := int64(0); i < 4; i++ {
        start := i * chunkSize
        end := start + chunkSize - 1
        if i == 3 {
            end = totalSize - 1
        }
        
        filename := "part_" + strconv.FormatInt(i, 10) + ".tmp"
        go downloadPartial(url, start, end, filename)
    }
}

应用场景

1. 大文件下载

// 支持暂停和恢复的下载器
type ResumableDownloader struct {
    URL        string
    FilePath   string
    ChunkSize  int64
}

func (d *ResumableDownloader) Download() error {
    // 检查已下载部分
    downloaded := d.getDownloadedSize()
    
    // 继续从断点下载
    req, _ := http.NewRequest("GET", d.URL, nil)
    req.Header.Set("Range", fmt.Sprintf("bytes=%d-", downloaded))
    
    // ... 实现续传逻辑
}

2. 视频流媒体

func serveVideo(w http.ResponseWriter, r *http.Request) {
    // 支持视频播放器的范围请求
    if r.Header.Get("Range") != "" {
        // 返回206和视频片段
        w.Header().Set("Content-Type", "video/mp4")
        // ... 处理范围请求
    }
}

3. 多线程下载加速

func concurrentDownload(url string, numWorkers int) {
    // 获取文件大小
    resp, _ := http.Head(url)
    totalSize, _ := strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 64)
    
    chunkSize := totalSize / int64(numWorkers)
    
    // 创建下载任务
    for i := 0; i < numWorkers; i++ {
        start := int64(i) * chunkSize
        end := start + chunkSize - 1
        if i == numWorkers-1 {
            end = totalSize - 1
        }
        
        go downloadChunk(url, start, end, i)
    }
}

注意事项

  1. 服务器必须设置Accept-Ranges: bytes
  2. 范围无效时返回416状态码
  3. 支持多范围请求时使用multipart/byteranges内容类型
  4. 确保正确处理字节范围边界

206状态码在需要高效传输大文件的场景中非常有用,特别是云存储、视频流媒体和大型软件分发等应用。

回到顶部