Jak zasoby przesyłania strumieniowego mieszczą się w paradygmacie RESTful?

101

Dzięki usłudze RESTful można tworzyć, odczytywać, aktualizować i usuwać zasoby. To wszystko działa dobrze, gdy masz do czynienia z czymś w rodzaju zasobów bazy danych - ale jak to się przekłada na przesyłanie strumieniowe danych? (A może tak?) Na przykład w przypadku wideo głupotą wydaje się traktowanie każdej klatki jako zasobu, który powinienem odpytywać pojedynczo. Raczej skonfigurowałbym połączenie przez gniazdo i przesyłam serię ramek. Ale czy to łamie paradygmat RESTful? A jeśli chcę mieć możliwość przewijania strumienia do tyłu lub do przodu? Czy jest to możliwe w ramach paradygmatu RESTful? A więc: jak zasoby przesyłania strumieniowego mieszczą się w paradygmacie RESTful?

W ramach implementacji przygotowuję się do stworzenia takiej usługi przesyłania strumieniowego danych i chcę się upewnić, że robię to w „najlepszy sposób”. Jestem pewien, że ten problem został już wcześniej rozwiązany. Czy ktoś może wskazać mi dobry materiał?

JnBrymn
źródło
2
Którą opcję ostatecznie wybrałeś? Czy spojrzałeś na gRPc? Obsługuje dwukierunkowe przesyłanie strumieniowe.
Mac

Odpowiedzi:

80

Nie udało mi się znaleźć materiałów o prawdziwie RESTful streaming - wygląda na to, że wyniki dotyczą głównie delegowania streamingu do innej usługi (co nie jest złym rozwiązaniem). Zrobię więc co w mojej mocy, aby sobie z tym poradzić - pamiętaj, że streaming nie jest moją domeną, ale spróbuję dodać moje 2 centy.

W aspekcie streamingu myślę, że musimy rozdzielić problem na dwie niezależne części:

  1. dostęp do zasobów medialnych (metadane)
  2. dostęp do samego medium / strumienia (dane binarne)

1.) Dostęp do zasobów multimedialnych
Jest to całkiem proste i można je obsłużyć w czysty i RESTful sposób. Jako przykład załóżmy, że będziemy mieć API oparte na XML, które umożliwia nam dostęp do listy strumieni:

GET /media/

<?xml version="1.0" encoding="UTF-8" ?>
<media-list uri="/media">
    <media uri="/media/1" />
    <media uri="/media/2" />
    ...
</media-list>

... a także do poszczególnych strumieni:

GET /media/1

<?xml version="1.0" encoding="UTF-8" ?>
<media uri="/media/1">
    <id>1</id>
    <title>Some video</title>
    <stream>rtsp://example.com/media/1.3gp</stream>
</media>

2.) Dostęp do samego medium / strumienia
Jest to bardziej problematyczny bit. Wskazałeś już jedną opcję w swoim pytaniu, a mianowicie zezwolenie na dostęp do ramek indywidualnie za pośrednictwem RESTful API. Chociaż może to zadziałać, zgadzam się z tobą, że nie jest to opłacalna opcja.

Myślę, że można dokonać wyboru pomiędzy:

  1. delegowanie streamingu do dedykowanej usługi poprzez wyspecjalizowany protokół przesyłania strumieniowego (np. RTSP)
  2. wykorzystując opcje dostępne w HTTP

Uważam, że ten pierwszy jest bardziej efektywnym wyborem, chociaż wymaga dedykowanej usługi przesyłania strumieniowego (i / lub sprzętu). Może to być trochę na skraju tego, co jest uważane za RESTful, jednak pamiętaj, że nasze API jest RESTful we wszystkich aspektach i nawet jeśli dedykowana usługa przesyłania strumieniowego nie jest zgodna z jednolitym interfejsem (GET / POST / PUT / DELETE), nasze API robi. Nasze API umożliwia nam odpowiednią kontrolę nad zasobami i ich metadanymi poprzez GET / POST / PUT / DELETE, a także zapewniamy linki do usługi przesyłania strumieniowego (w ten sposób zgodnie z aspektem łączności REST).

Ta ostatnia opcja - przesyłanie strumieniowe przez HTTP - może nie być tak wydajna jak powyższa, ale zdecydowanie jest możliwa. Z technicznego punktu widzenia nie różni się to tak bardzo od umożliwienia dostępu do dowolnej formy treści binarnej za pośrednictwem protokołu HTTP. W takim przypadku nasze API zapewni link do zasobu binarnego dostępnego przez HTTP, a także poinformuje nas o rozmiarze zasobu:

GET /media/1

<?xml version="1.0" encoding="UTF-8" ?>
<media uri="/media/1">
    <id>1</id>
    <title>Some video</title>
    <bytes>1048576</bytes>
    <stream>/media/1.3gp</stream>
</media>

Klient może uzyskać dostęp do zasobu za pośrednictwem protokołu HTTP przy użyciu GET /media/1.3gp. Jedną z opcji jest pobranie przez klienta całego zasobu - pobieranie progresywne HTTP . Bardziej przejrzystą alternatywą byłoby uzyskanie przez klienta dostępu do zasobu w fragmentach przy użyciu nagłówków zakresu HTTP . W przypadku pobrania drugiej porcji 256 KB pliku o wielkości 1 MB żądanie klienta wyglądałoby następująco:

GET /media/1.3gp
...
Range: bytes=131072-262143
...

Serwer obsługujący zakresy odpowiadałby wówczas nagłówkiem Content-Range , po którym następuje częściowa reprezentacja zasobu:

HTTP/1.1 206 Partial content
...
Content-Range: bytes 131072-262143/1048576
Content-Length: 1048576
...

Zwróć uwagę, że nasze API poinformowało już klienta o dokładnym rozmiarze pliku w bajtach (1 MB). W przypadku, gdy klient nie znałby rozmiaru zasobu, powinien najpierw zadzwonić HEAD /media/1.3gpw celu określenia rozmiaru, w przeciwnym razie ryzykuje odpowiedź serwera z 416 Requested Range Not Satisfiable.

MicE
źródło
2
Wow ... to świetna informacja. Zwróciłeś moją uwagę na kilka nowych sposobów myślenia o tym. Nie wiedziałem również o protokole przesyłania strumieniowego w czasie rzeczywistym.
JnBrymn
1
Żaden problem, cieszę się, że mogłem pomóc. Należy jednak pamiętać, że nie miałem jeszcze okazji osobiście pracować z protokołami przesyłania strumieniowego (z wyjątkiem progresywnego przesyłania strumieniowego przez HTTP). Jako przykład wybrałem RTSP, nie wiem, czy może się przydać w twoim konkretnym scenariuszu. Możesz zadać kolejne pytanie SO dotyczące protokołów przesyłania strumieniowego. Wikipedia oferuje również dobry punkt wyjścia do innych protokołów - zobacz sekcje „Problemy z protokołami” i „Zobacz także” tutaj: en.wikipedia.org/wiki/Streaming_Media
MicE
1
Dziękuję, to jest zdecydowanie najprostsze i techniczne wyjaśnienie.
silentsudo