下面是一个支持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助手提供,问题来源于学员提问




