如何使用 Go 提供 http 部分内容?
How to serve http partial content with Go?
我有一个用 go 编写的网络服务器,我正在提供来自不同来源(本地、其他服务器、S3)的一些音频文件。我想为此文件启用部分内容服务,以便 HTML 音频标签能够搜索和循环播放。
我怎样才能做到这一点?我知道 http
包 ServeContent
函数可以执行此操作,但我如何通过自己提供文件来执行此操作?我需要在没有这个的情况下这样做,以便我可以使用相同的处理程序提供来自不同来源的文件。
提供部分内容 non-trivial。有关介绍,请参阅维基百科上的 Byte serving。您必须处理特定的状态代码和 headers(请求和响应),这并不难,但您不应该自己浪费时间。
如果要提供(或提供自)的内容是一个文件,您可以像您提到的那样使用 http.ServeFile()
,它处理提供部分内容(范围请求)。
如果要提供的内容不是文件形式,那么 http.ServeContent()
是你的朋友:
func ServeContent(w ResponseWriter, req *Request,
name string, modtime time.Time, content io.ReadSeeker)
是的,它还处理提供部分内容(范围请求):
The main benefit of ServeContent over io.Copy is that it handles Range requests properly, sets the MIME type, and handles If-Modified-Since requests.
您需要做的就是提供 io.ReadSeeker
"view" 您的内容,这是必需的,以便实现可以 "jump" 到客户请求的部分,需要服务的部分。您可能会问:如何做到这一点?
bytes
package contains a type that implements 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()
是为了填充传递的切片(以提供实际内容)。请注意,这些方法可能会被多次调用,因此您必须跟踪您在内容中的位置(来源)。如果您选择走这条路,请阅读链接接口的文档以确保您满足接口的 "general contract" 以避免意外错误。
我有一个用 go 编写的网络服务器,我正在提供来自不同来源(本地、其他服务器、S3)的一些音频文件。我想为此文件启用部分内容服务,以便 HTML 音频标签能够搜索和循环播放。
我怎样才能做到这一点?我知道 http
包 ServeContent
函数可以执行此操作,但我如何通过自己提供文件来执行此操作?我需要在没有这个的情况下这样做,以便我可以使用相同的处理程序提供来自不同来源的文件。
提供部分内容 non-trivial。有关介绍,请参阅维基百科上的 Byte serving。您必须处理特定的状态代码和 headers(请求和响应),这并不难,但您不应该自己浪费时间。
如果要提供(或提供自)的内容是一个文件,您可以像您提到的那样使用 http.ServeFile()
,它处理提供部分内容(范围请求)。
如果要提供的内容不是文件形式,那么 http.ServeContent()
是你的朋友:
func ServeContent(w ResponseWriter, req *Request,
name string, modtime time.Time, content io.ReadSeeker)
是的,它还处理提供部分内容(范围请求):
The main benefit of ServeContent over io.Copy is that it handles Range requests properly, sets the MIME type, and handles If-Modified-Since requests.
您需要做的就是提供 io.ReadSeeker
"view" 您的内容,这是必需的,以便实现可以 "jump" 到客户请求的部分,需要服务的部分。您可能会问:如何做到这一点?
bytes
package contains a type that implements 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()
是为了填充传递的切片(以提供实际内容)。请注意,这些方法可能会被多次调用,因此您必须跟踪您在内容中的位置(来源)。如果您选择走这条路,请阅读链接接口的文档以确保您满足接口的 "general contract" 以避免意外错误。