本来mp4文件是直接nginx代理的,但是最近把图片音视频迁移到家里的minio里了,nginx不好直接代理到,索性实现个接口
直接上代码, 看注释得了。
func videoServ(ctx *gin.Context) {
filepath := ctx.Param("filepath")
key := strings.Join([]string{config.CONFIG_INTANCE.DataDir, "videos", filepath}, "/")
// 渠道object
obj, err := storage.ReadFromMC(key)
if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, err)
return
}
// 取到文件大小
fileInfo, err := obj.Stat()
fileSize := fileInfo.Size
// 获取浏览器的请求头
rangeHeader := ctx.GetHeader("Range")
// 空的就按全部大小来写入
if rangeHeader == "" {
// No Range header, send full file
ctx.Header("Content-Length", strconv.FormatInt(fileInfo.Size, 10))
ctx.Header("Accept-Ranges", "bytes")
ctx.Header("Content-Type", "video/mp4")
ctx.DataFromReader(http.StatusOK, fileInfo.Size, "video/mp4", obj, nil)
return
}
// 解析Range头
rangeSpec := strings.TrimPrefix(rangeHeader, "bytes=")
startEnd := strings.SplitN(rangeSpec, "-", 2)
// 获取开始值
start, err := strconv.ParseInt(startEnd[0], 10, 64)
if err != nil || start < 0 {
ctx.JSON(http.StatusRequestedRangeNotSatisfiable, gin.H{"error": "Invalid start byte range"})
return
}
// 获取结束值
var end int64
if len(startEnd) == 2 && startEnd[1] != "" {
end, err = strconv.ParseInt(startEnd[1], 10, 64)
// 超了就按最大
if err != nil || end > fileSize-1 {
end = fileSize - 1
}
} else {
// 没有 也是最大
end = fileSize - 1
}
// 值不对
if start > end || start > fileSize-1 {
ctx.JSON(http.StatusRequestedRangeNotSatisfiable, gin.H{"error": "Requested range not satisfiable"})
return
}
// 设置响应头
contentLength := end - start + 1
// bytes start-end/total
ctx.Header("Content-Range", fmt.Sprintf("bytes %d-%d/%d", start, end, fileSize))
// acccept 头
ctx.Header("Accept-Ranges", "bytes")
ctx.Header("Content-Length", strconv.FormatInt(contentLength, 10))
ctx.Header("Content-Type", "video/mp4")
// 206 code
ctx.Status(http.StatusPartialContent)
// 跳到开始的地方
_, err = obj.Seek(start, io.SeekStart)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Could not seek to start byte"})
return
}
// 写入lenght长度
io.CopyN(ctx.Writer, obj, contentLength)
obj.Close()
}