Заявката към HLS/DASH URL за хоствано от Reddit видео през XHR води до грешка „CORS header „Access-Control-Allow-Origin“ missing“

Опитвам се да използвам библиотеката hls.js за показване на хоствани в Reddit видеоклипове от плейлиста HLS/DASH. Въпреки това достъпът до който и да е URL адрес на Reddit HLS/DASH, като например този през XHR, ще бъде неуспешен поради това, което казва грешката, е нарушение на правилата за същия произход:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://v.redd.it/5r0nz8sywgl41/DASHPlaylist.mpd. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).

Странното е, че заявката преди GET е OPTIONS, която връща заглавката Access-Control-Allow-Origin с правилния URL адрес на източника. Виждам отговора в конзолата за разработчици, но заявката все още е „неуспешна“. Ако използвам разширението „Allow CORS: Access-Control-Allow-Origin“, всичко работи добре. Какво правя неправилно?

OPTIONS заглавки на заявка:

Host: v.redd.it
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0
Accept: */*
Accept-Language: lt,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate, br
Access-Control-Request-Method: GET
Access-Control-Request-Headers: authorization
Referer: http://localhost:3000/
Origin: http://localhost:3000
DNT: 1
Connection: keep-alive
Save-Data: on
Pragma: no-cache
Cache-Control: no-cache
TE: Trailers

Заглавки на отговор OPTIONS:

HTTP/2 200 OK
retry-after: 0
access-control-allow-origin: http://localhost:3000
access-control-allow-headers: authorization
access-control-allow-methods: GET
access-control-max-age: 3000
date: Sun, 08 Mar 2020 18:40:29 GMT
via: 1.1 varnish
x-served-by: cache-hhn4029-HHN
x-cache: HIT
x-cache-hits: 0
x-timer: S1583692829.044409,VS0,VE0
server: snooserv
accept-ranges: bytes
x-cdn-server-region: EU-East
x-cdn-client-region: EU
x-cdn-name: fastly
access-control-expose-headers: x-cdn-server-region, x-cdn-client-region, x-cdn-name
cache-control: public, max-age=604800, s-maxage=86400, must-revalidate
vary: Access-Control-Request-Headers, Access-Control-Request-Method,Origin
content-length: 0
X-Firefox-Spdy: h2

GET заглавки на заявка:

Host: v.redd.it
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0
Accept: */*
Accept-Language: lt,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate, br
Referer: http://localhost:3000/
Authorization: Bearer --------------------------- (actual token here)
Origin: http://localhost:3000
DNT: 1
Connection: keep-alive
Save-Data: on
Pragma: no-cache
Cache-Control: no-cache
TE: Trailers

ВЗЕМЕТЕ заглавки на отговора:

HTTP/2 200 OK
last-modified: Sun, 08 Mar 2020 15:34:11 GMT
etag: "0abfb243cb8d03188bf34ff29d6d4af8"
content-type: application/dash+xml
via: 1.1 varnish
date: Sun, 08 Mar 2020 18:40:29 GMT
via: 1.1 varnish
x-served-by: cache-bwi5138-BWI, cache-hhn4029-HHN
x-cache: HIT, HIT
x-cache-hits: 2, 34
x-timer: S1583692829.127808,VS0,VE0
server: snooserv
accept-ranges: bytes
x-cdn-server-region: EU-East
x-cdn-client-region: EU
x-cdn-name: fastly
access-control-expose-headers: x-cdn-server-region, x-cdn-client-region, x-cdn-name
cache-control: public, max-age=604800, s-maxage=86400, must-revalidate
vary: Origin
content-length: 1976
X-Firefox-Spdy: h2

ПОЛУЧЕТЕ отговор:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<MPD mediaPresentationDuration="PT15.034S" minBufferTime="PT1.500S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" type="static" xmlns="urn:mpeg:dash:schema:mpd:2011">
    <Period duration="PT15.034S">
        <AdaptationSet segmentAlignment="true" subsegmentAlignment="true" subsegmentStartsWithSAP="1">
            <Representation bandwidth="1172841" codecs="avc1.4d401f" frameRate="30" height="480" id="VIDEO-1" mimeType="video/mp4" startWithSAP="1" width="720">
                <BaseURL>DASH_480</BaseURL>
                <SegmentBase indexRange="913-992" indexRangeExact="true">
                    <Initialization range="0-912"/>
                </SegmentBase>
            </Representation>
            <Representation bandwidth="784684" codecs="avc1.4d401e" frameRate="30" height="360" id="VIDEO-2" mimeType="video/mp4" startWithSAP="1" width="540">
                <BaseURL>DASH_360</BaseURL>
                <SegmentBase indexRange="915-994" indexRangeExact="true">
                    <Initialization range="0-914"/>
                </SegmentBase>
            </Representation>
            <Representation bandwidth="592784" codecs="avc1.4d401e" frameRate="30" height="240" id="VIDEO-3" mimeType="video/mp4" startWithSAP="1" width="360">
                <BaseURL>DASH_240</BaseURL>
                <SegmentBase indexRange="915-994" indexRangeExact="true">
                    <Initialization range="0-914"/>
                </SegmentBase>
            </Representation>
            <Representation bandwidth="91690" codecs="avc1.4d400a" frameRate="30" height="96" id="VIDEO-4" mimeType="video/mp4" startWithSAP="1" width="144">
                <BaseURL>DASH_96</BaseURL>
                <SegmentBase indexRange="912-991" indexRangeExact="true">
                    <Initialization range="0-911"/>
                </SegmentBase>
            </Representation>
        </AdaptationSet>
    </Period>
</MPD>

Много благодаря за твоята помощ.


person Emilis Kiškis    schedule 08.03.2020    source източник


Отговори (1)


Проблемът е просто: отговорът от https://v.redd.it/5r0nz8sywgl41/DASHPlaylist.mpd на заявката GET от вашия код не включва заглавката на отговора Access-Control-Allow-Origin. Странно обаче, той включва заглавката на отговора Access-Control-Expose-Headers. Така че причината е просто, че сървърът е неправилно конфигуриран; всъщност не е активиран правилно CORS.

По-конкретно: въпреки че сървърът изпраща Access-Control-Allow-Origin хедър в отговор на OPTIONS preflight, това само по себе си не е достатъчно, за да накара браузърите да позволят на кода ви за интерфейс да получи достъп до отговора на действителната заявка GET във вашия код. За да работи кодът ви, сървърът трябва също да изпрати заглавката Access-Control-Allow-Origin в отговор на тази GET заявка.

Но всъщност можете да заобиколите неправилната конфигурация на https://v.redd.it и да получите достъп до HLS/DASH URL адресите на Reddit от вашия код на интерфейса, без да се нуждаете от разширение на браузъра — като направите заявката си чрез CORS прокси, както в следния пример.

const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "https://v.redd.it/5r0nz8sywgl41/DASHPlaylist.mpd";
fetch(proxyurl + url)
.then(response => response.text())
.then(contents => console.log(contents))

За обяснение вижте отговора на https://stackoverflow.com/a/43881141/441757.

Можете лесно да стартирате свой собствен прокси с помощта на код от https://github.com/Rob--W/cors-anywhere/ и можете бързо да внедрите свой собствен прокси към Heroku буквално само за 2-3 минути, с 5 команди:

git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master

След като изпълните тези команди, ще се окажете с вашия собствен CORS Anywhere сървър, работещ на, например, https://cryptic-headland-94862.herokuapp.com/. Така че вместо да префиксирате URL адреса на вашата заявка с https://cors-anywhere.herokuapp.com, добавете го вместо това с URL адреса за вашия собствен екземпляр; напр. https://cryptic-headland-94862.herokuapp.com/https://example.com.

person sideshowbarker    schedule 09.03.2020
comment
Благодаря за допълнителната информация. Това обаче не нарушава ли правилата за достъп до съдържанието на Reddit или нещо подобно? - person Emilis Kiškis; 12.03.2020
comment
Не знам каква политика може да има Reddit, която да ви забранява да използвате прокси (ваше собствено или на някой друг), за да правите заявки към техния сайт. Вече можете да правите заявки към сървъра на Reddit, като използвате curl или wget или който и да е HTTP клиент или която и да е среда за изпълнение от страна на сървъра, без да се натъквате на проблеми. Единственото място, където се налагат ограничения за достъп до URL адреси на Reddit, са браузърите. - person sideshowbarker; 12.03.2020
comment
Или да формулираме проблема с правилата с други термини: Наличието на заглавката на отговора Access-Control-Allow-Origin е просто изричен индикатор към браузърите за премахване на ограниченията, които браузърите вече налагат по подразбиране. Но отсъствието на заглавката на отговора Access-Control-Allow-Origin не е изричен индикатор, че сайтът умишлено възнамерява да забрани достъпа на отговорите на предния JavaScript код. Вместо това просто собствениците на сайтове просто са пропуснали да отделят време за активиране на CORS на своя сайт или че са се опитали да активират CORS на сайта, но вместо това са го конфигурирали неправилно. - person sideshowbarker; 12.03.2020
comment
Така че CORS е по-скоро като инструмент за клиенти, за да направят сърфирането в неизвестни източници по-безопасно? - person Emilis Kiškis; 12.03.2020
comment
CORS е проектиран почти единствено за интранет мрежи, и по-специално, атаки за ескалация на привилегии на объркани заместници в интранет мрежи. Проблемният случай, който CORS е проектиран да адресира, е случаят на интранет, погрешно приемащ, че всяка заявка, която идва от източник в интранета, зад защитната стена, е „безопасен“ клиент – и така наивно/несигурно извършва удостоверяване само на базата на IP адрес. Но злонамерено уеб приложение на трета страна може да стартира от машината на потребителя в интранета, от IP адреса на този потребител, с привилегиите на този потребител. - person sideshowbarker; 12.03.2020