我正在尝试使用hls.js库显示来自HLS / DASH播放列表的Reddit托管视频。然而,访问任何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,它确实返回带有正确原始URL的Access-Control-Allow-Origin标头。我可以在开发人员控制台中看到响应,但是请求仍然“失败”。如果我使用“允许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
GET响应头:
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
GET响应:
<?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>
非常感谢你的帮助。
问题只是:从响应https://v.redd.it/5r0nz8sywgl41/DASHPlaylist.mpd
到GET
从您的代码的请求不包括Access-Control-Allow-Origin
响应头。但是奇怪的是,它确实包含了Access-Control-Expose-Headers
响应头。因此,原因仅在于服务器配置错误。实际上并没有正确启用CORS。
具体来说:即使服务器发送了一个Access-Control-Allow-Origin
标头来响应OPTIONS
预检,仅凭它本身还不足以使浏览器允许您的前端代码访问对代码中实际GET
请求的响应。为了使代码正常工作,服务器还必须发送Access-Control-Allow-Origin
标头以响应该GET
请求。
但是实际上,您可以解决https://v.redd.it
配置错误并从前端代码访问Reddit HLS / DASH URL,而无需使用浏览器扩展,方法是通过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/中的代码轻松运行自己的代理,并且可以使用5条命令在2-3分钟内将您自己的代理快速部署到Heroku中:
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。
感谢您提供其他信息。但是,这是否违反Reddit内容访问策略或类似的做法?
我不知道Reddit会采取什么政策来禁止您使用代理(您自己或他人的代理)向其站点发出请求。您已经可以使用curl或wget或任何HTTP客户端或任何服务器端运行时环境向Reddit服务器发出请求,而不会遇到任何问题。对访问Reddit URL施加任何限制的唯一地方是浏览器。
或者用其他方式来解决策略问题:Access-Control-Allow-Origin响应标头的存在只是浏览器的一个明确指示器,以解除默认情况下浏览器已经施加的限制。但是,缺少Access-Control-Allow-Origin响应标头并不能明确表明该站点有意禁止前端JavaScript代码访问响应。取而代之的是,网站所有者只是忽略了花一些时间来启用其网站的CORS,或者只是他们尝试了启用CORS的网站,但配置错误。
因此,CORS更像是使客户更安全地浏览未知来源的工具?
CORS几乎完全是为Intranet设计的,特别是Intranet内部的混淆代理特权升级攻击。CORS旨在解决的问题是Intranet的情况,它假定来自Intranet内部源的任何请求(在防火墙之后)都是“安全”客户端,因此天真/不安全地仅基于IP进行身份验证地址。但是,恶意的第三方Web应用程序可以使用该用户的特权,从Intranet内的用户计算机,该用户的IP地址运行。