如何使用Go提供HTTP部分内容服务?

13

我有一个用Go编写的Web服务器,正在从不同的来源(本地,其他服务器,S3)提供一些音频文件。我想启用这些文件的部分内容服务,以便HTML音频标签可以进行搜索和循环播放。

我该如何实现呢?我知道http包中的ServeContent函数可以实现这一功能,但我如何自己提供文件来实现呢?我需要这样做,以便我可以使用相同的处理程序从不同的来源提供文件。

1个回答

31

提供部分内容是不容易的。请参见维基百科上的Byte serving进行介绍。您必须处理特定的状态码和标头(请求和响应),这并不太难,但您不应该浪费时间自己处理。

如果要提供或从提供的内容是文件,则可以使用http.ServeFile(),正如您所提到的,它可以处理提供部分内容(范围请求)。

如果要提供的内容不存在文件中,则http.ServeContent()会帮到您:

func ServeContent(w ResponseWriter, req *Request,
    name string, modtime time.Time, content io.ReadSeeker)

是的,它还可以处理部分内容(范围请求):

ServeContent相对于io.Copy的主要优点在于它可以正确处理范围请求、设置MIME类型并处理If-Modified-Since请求。

你只需要提供一个io.ReadSeeker“视图”来展示你的内容,这是必需的,以便实现可以“跳转”到客户端请求的部分,也就是需要提供的部分。你可能会问:如何做到这一点?

bytes包含了一个实现了io.ReadSeeker的类型:bytes.Reader

例如,如果你有一个[]byte的内容,你可以像这样获取一个io.ReadSeeker

var content []byte
// fill content
r := bytes.NewReader(content)

如果您没有整个内容作为[]byte,该怎么办?其中一个选项是提供一个自己的类型值,实现io.ReadSeekerio.ReadSeeker是:
type ReadSeeker interface {
    Reader
    Seeker
}

io.Reader 包含一个方法:

Read(p []byte) (n int, err error)

io.Seeker 同样包含一个方法:

Seek(offset int64, whence int) (int64, error)

您的内容可以在某个地方以某种方式访问,您知道如何操作。当需要从您的内容中获取特定部分(位置)时,会调用Seek()函数通知您,然后再调用Read()函数以便您填充传递的切片(提供实际内容)。请注意,这些方法可能会被多次调用,因此您必须跟踪自己在内容(源)中的位置。如果您选择这条路,请阅读链接接口的文档,以确保您符合接口的“一般契约”,避免出现意外错误。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接