CloudFrontの署名付きCookieの設定方法などについては、ネット上に沢山の記事があるかと思いますので、割愛します。
構成としては、ブラウザから自前のサーバ( https://hoge.com )にアクセスしCookieをブラウザに食わせ、その後hls.jsを使ってCloudFront( https://streaming.hoge.com )からストリーミング配信する形。
とてもシンプルだし簡単にできるかと思っていたのだけど、自前のサーバがブラウザに食わせたCookieをhls.jsがCloudFrontに送ってくれないことが判明。
調べてみたところ、
https://github.com/video-dev/hls.js/issues/246
に書かれているように、hls.jsは初期設定のままだとCookieを送ってくれないらしい。
というわけで、以下のコードを書く。
let config = {
debug: true,
xhrSetup: function ( xhr, url ) {
xhr.withCredentials = true; // do send cookie
}
};
let hls = new Hls( config );
これで無事にCookieが送られるようになったものの、今度はCORSエラーが発生。
CloudFrontのオリジンはS3で、S3のCORS設定は以下のようにしている。
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"PUT",
"POST",
"GET"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": []
}
]
m3u8ファイルのレスポンスヘッダにも、きちんとAccess-Control-Allow-Origin:*が含まれている。
で、更に調べてみた結果、以下のページを発見。
https://github.com/video-dev/hls.js/issues/329
クレデンシャルフラグがtrueの時というのが、正直なところきちんと理解できているわけではないんだけど、ようするにAccess-Control-Allow-Originにワイルドカードを設定しているのがダメで、きちんとドメインを設定する必要があるらしい。
となると、S3のCORS設定だとできないので、CloudFront Functionsに以下のコードを設定して、Viewer Responseに設定する。
function handler(event) {
var request = event.request;
var response = event.response;
if (request.headers['origin']) {
request.headers['origin']) {
response.headers['access-control-allow-origin'] = {value: request.headers['origin'].value};
}
return response;
}
これで解決かと思いきや、引き続きCORSエラーが発生。
ブラウザのエラーログには以下のログが吐かれる。
The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
ようするに、レスポンスヘッダのAccess-Control-Allow-Credentialsにtrueを設定する必要があるとのこと。
というわけなので、先程のCloudFront Functionsを修正。
function handler(event) {
var request = event.request;
var response = event.response;
if (request.headers['origin']) {
request.headers['origin']) {
response.headers['access-control-allow-origin'] = {value: request.headers['origin'].value};
response.headers['access-control-allow-credentials'] = {value: 'true'};
}
return response;
}
これで、やっとストリーミング配信が正常にできるようになりました。
とりあえず動いたものの、仕組みについては完璧に理解できているわけではないので、間違いなどありましたらご指摘頂けますと嬉しいです。