我有一个用go语言编写的网络服务器,并且正在提供来自不同来源(本地,其他服务器,S3)的一些音频文件。我想为此文件提供部分内容,以便HTML音频标签能够搜索和循环。
我该如何实现?我知道http包ServeContent功能可以做到这一点,但是我如何通过自己提供文件来实现呢?我需要在没有此操作的情况下执行此操作,以便可以使用相同的处理程序处理来自不同来源的文件。
http
ServeContent
提供部分内容并非易事。有关介绍,请参见Wikipedia上的Byte服务。您必须处理特定的状态代码和标头(请求和响应),这虽然不太难,但是您不应该浪费时间自己做。
如果要提供(或从中提供)的内容是文件,则可以http.ServeFile()按照您提到的那样使用该文件,该文件可以处理部分内容(范围请求)。
http.ServeFile()
如果要提供的内容不是文件形式,那么http.ServeContent()您的朋友是:
http.ServeContent()
func ServeContent(w ResponseWriter, req *Request, name string, modtime time.Time, content io.ReadSeeker)
是的,它还处理了部分内容的提供(范围请求):
ServeContent优于io.Copy的主要好处在于,它可以正确处理Range请求,设置MIME类型并处理If-Modified-Since请求。
您需要做的就是提供内容的io.ReadSeeker“视图”,这是必需的,以便实现可以“跳转”到客户端请求的部分,即需要提供服务的部分。您可能会问:该怎么做?
io.ReadSeeker
该bytes包包含一个实现的类型io.ReadSeeker:bytes.Reader。
bytes
bytes.Reader
因此,例如,如果您的内容为[]byte,则可以这样获得io.ReadSeeker:
[]byte
var content []byte // fill content r := bytes.NewReader(content)
如果您没有全部内容[]byte呢?一种选择是提供您自己实现的类型的值io.ReadSeeker。
io.ReadSeeker 是:
type ReadSeeker interface { Reader Seeker }
io.Reader 包含一种方法:
io.Reader
Read(p []byte) (n int, err error)
io.Seeker 还包含一种方法:
io.Seeker
Seek(offset int64, whence int) (int64, error)
您的内容可以在某个地方访问,无论如何,您都知道。Seek()被调用以使您知道内容中需要什么部分(位置),并被Read()调用以便可以填充传递的切片(以提供实际内容)。请注意,这些方法可能会被多次调用,因此您必须跟踪内容(源)中的位置。如果您选择沿着这条路走,请阅读链接接口的文档,以确保您符合接口的“一般合同”,以避免出现意外错误。
Seek()
Read()