本来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()
}
image.png
QQ20241128-162830.png