2016-04-11 8 views
3

У меня есть веб-сервер, написанный в go, и я обслуживаю некоторые аудиофайлы из разных источников (локальные, другие серверы, S3). Я хочу включить частичный контент для этих файлов, чтобы аудиотексты HTML могли искать и петли.Как обслуживать HTTP-контент с помощью Go?

Как я могу достичь этого? Я знаю, что это делает http пакет ServeContent, но как я могу это сделать, обслуживая файлы самостоятельно? Мне нужно сделать это без этого, чтобы я мог обслуживать файлы из разных источников с помощью одного и того же обработчика.

ответ

11

Обслуживание частичного содержимого нетривиально. См. 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() вызывается так, что вы можете заполнить пройденный фрагмент (чтобы предоставить фактический контент). Обратите внимание, что эти методы можно вызывать несколько раз, поэтому вам нужно отслеживать, где вы находитесь в своем контенте (источник).Если вы решите пойти по этому пути, прочитайте документ связанных интерфейсов, чтобы убедиться, что вы отвечаете «генеральному контракту» интерфейсов, чтобы избежать неожиданных ошибок.