How to serve http partial content with Go?

I have a web server written in go, and I serve some audio files from different sources (local, other servers, S3). I want to include partial content for these files so that HTML audio texts can search and cite.

How can I achieve this? I know that the http package ServeContent function does this, but how can I do this by serving the files myself? I need to do this without this so that I can serve files from different sources with the same handler.

+3
source share
1 answer

Serving partial content is non-trivial. See Byte showing on wikipedia for an introduction. You should process certain status codes and headers (both the request and the response), which is not too difficult, but you should not waste your time on this.

If the content to submit (or submit) from a file is a file, you can use http.ServeFile() just as you mentioned, which handles partial content (range requests).

If the content you want to serve is missing as a file, then http.ServeContent() is your friend:

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

And yes, it also handles partial content (range requests):

The main advantage of ServeContent over io.Copy is that it handles range requests correctly, sets the MIME type, and processes If-Modified-Since requests.

All you have to do is provide io.ReadSeeker β€œpresentation” of your content, this is necessary so that the implementation can β€œjump” to the part requested by the client, the part to be submitted. You may ask: how to do this?

The bytes package contains a type that implements io.ReadSeeker : bytes.Reader .

So, for example, if you have content like []byte , you can get io.ReadSeeker as follows:

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

But what if you don't have all the content like []byte ? One option is to provide a value of your own type that implements io.ReadSeeker .

io.ReadSeeker :

 type ReadSeeker interface { Reader Seeker } 

io.Reader contains one method:

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

io.Seeker also contains one method:

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

Your content is available somewhere, anyway, you know how to do it. Seek() is called so that you know what part (position) is required from your content, and Read() is called so that you can fill in the passed fragment (to provide the actual content). Please note that these methods can be called several times, so you need to track where you are in your content (source). If you decide to go this route, read the document on related interfaces to make sure that you meet the "general contract" of interfaces in order to avoid unexpected errors.

+11
source

All Articles