我有一个用Go编写的Web服务器,正在从不同的来源(本地,其他服务器,S3)提供一些音频文件。我想启用这些文件的部分内容服务,以便HTML音频标签可以进行搜索和循环播放。
我该如何实现呢?我知道http
包中的ServeContent
函数可以实现这一功能,但我如何自己提供文件来实现呢?我需要这样做,以便我可以使用相同的处理程序从不同的来源提供文件。
我有一个用Go编写的Web服务器,正在从不同的来源(本地,其他服务器,S3)提供一些音频文件。我想启用这些文件的部分内容服务,以便HTML音频标签可以进行搜索和循环播放。
我该如何实现呢?我知道http
包中的ServeContent
函数可以实现这一功能,但我如何自己提供文件来实现呢?我需要这样做,以便我可以使用相同的处理程序从不同的来源提供文件。
提供部分内容是不容易的。请参见维基百科上的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.ReadSeeker
。
io.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()
函数以便您填充传递的切片(提供实际内容)。请注意,这些方法可能会被多次调用,因此您必须跟踪自己在内容(源)中的位置。如果您选择这条路,请阅读链接接口的文档,以确保您符合接口的“一般契约”,避免出现意外错误。