ZBLOG

支持range功能单独写给我

下面是一个支持Range功能的Golang HTTP文件服务器的示例代码:

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"
)

const uploadDirectory = "./uploads" // 上传文件保存目录

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

func handleDownload(w http.ResponseWriter, r *http.Request) {
	filePath := filepath.Join(uploadDirectory, filepath.Base(r.URL.Path))
	fileStat, err := os.Stat(filePath)
	if err != nil || fileStat.IsDir() {
		http.NotFound(w, r)
		return
	}

	fSize := fileStat.Size()
	w.Header().Set("Accept-Ranges", "bytes")
	w.Header().Set("Content-Length", fmt.Sprintf("%d", fSize))

	rangeHeader := r.Header.Get("Range")
	if rangeHeader == "" {
		sendFile(filePath, w)
	} else {
		processRangeRequest(rangeHeader, filePath, w)
	}
}

func sendFile(filePath string, w http.ResponseWriter) {
	file, err := os.Open(filePath)
	if err != nil {
		http.Error(w, "Failed to open file for download", http.StatusInternalServerError)
		return
	}
	defer file.Close()

	io.Copy(w, file)
}

func processRangeRequest(rangeHeader string, filePath string, w http.ResponseWriter) {
	file, err := os.Open(filePath)
	if err != nil {
        http.Error(w,"Failed to open file for download",http.StatusInternalServerError)
        return 
    }
	defer file.Close()

	fSize := fileInfo.Size()
	startByte,endByte,err:=parseRangeHeader(rangeHeader,fSize)

	if err!=nil{
        w.Header().Set("Content-Range",fmt.Sprintf("bytes */%d",fSize))
        http.StatusRequestedRangeNotSatisfiable),w
        return 
    }

	rSize := endByte - startByte + 1

	w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", startByte, endByte, fSize))
	w.Header().Set("Content-Length", fmt.Sprintf("%d", rSize))
	w.WriteHeader(http.StatusPartialContent)

	_, err = file.Seek(startByte, io.SeekStart)
	if err != nil {
        http.Error(w,"Failed to seek file for range request",http.StatusInternalServerError)
        return 
    }

	io.CopyN(w, file, rSize)
}

func parseRangeHeader(rangeHeader string, fileSize int64) (startByte int64, endByte int64, err error) {
	const unitPrefix = "bytes="
	if len(rangeHeader) < len(unitPrefix) || rangeHeader[:len(unitPrefix)] != unitPrefix {
		err = fmt.Errorf("Invalid Range header")
		return
	}

	rangeStr := rangeHeader[len(unitPrefix):]
	rangeArr := strings.Split(rangeStr, "-")
	if len(rangeArr) != 2 {
		err = fmt.Errorf("Invalid Range header format")
		return
	}

	startStr := rangeArr[0]
	endStr := rangeArr[1]

	if startStr == "" && endStr == "" {
		err = fmt.Errorf("Invalid Range header values")
		return
	}

	startByte, err = strconv.ParseInt(startStr, 10, 64)
	if err != nil {
		startByte = fileSize - 1
	}

	endByte, err = strconv.ParseInt(endStr, 10, 64)
	if err != nil || endByte >= fileSize || (startStr == "" && endStr == "") {
		endByte = fileSize - 1
    }
    
    if startByte >endbyte{
        err=fmt.Errorf("Invalid Range header values")
    }

	return startByte, endByte, err
}

这个示例代码实现了一个支持Range功能的HTTP文件服务器。它会检查请求头中的Range字段,如果存在,则处理部分内容的响应。否则,返回完整的文件内容。

请注意,这只是一个简单的示例,并没有涵盖所有的异常处理和安全性考虑。在实际开发中,您可能需要添加更多的错误处理、身份验证和授权等功能。

希望这个示例对您有所帮助!如果有任何问题,请随时提问。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://golang.0voice.com/?id=12177

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?