TL;DR
iOS Safari は mp4 などのメディアコンテンツを HTTP 範囲リクエスト(206 Partial Content)
で受け取らないと再生してくれませんが
Cloudflare Pages は HTTP 範囲リクエスト に対応してないため 200 OK
で返してきます(response header に Accept-Ranges
があり、値が none
以外であれば、そのサーバーは HTTP 範囲リクエストに対応してることになります)。
その response を Service Worker でインターセプトして206に書き換えて解決します。
Nuxt × Workbox の場合
当方は普段 Nuxt × Workbox を利用しているためその場合の利用法になります(それ以外の環境の方は参考程度に御覧ください)
export default {
...
workbox: {
cachingExtensions: '~/plugins/workbox-range-request.js',
},
}
// メディアファイルのrangeRequest対応
const myPlugin = {
async fetchDidSucceed({ request, response }) {
if (response && response.status !== 206 && request.headers.has('range')) {
response = await workbox.rangeRequests.createPartialResponse(request, response)
}
return response
},
}
workbox.routing.registerRoute(
/\.(mp3|ogg|mp4|webm)/,
new workbox.strategies.CacheFirst({
cacheName: 'media-file-cache',
plugins: [
new workbox.rangeRequests.RangeRequestsPlugin(),
myPlugin,
],
}),
'GET'
)
本来 Cloudflare に限らず、 Service Worker を利用したサイトの動画を iOS で再生する際は
range request に対応する必要がありますが、
workbox の RangeRequestsPlugin では キャッシュされたレスポンス
のみのコントロールになってしまいます。
今回の Cloudflare の場合は キャッシュされる前のオリジンレスポンス
のコントロールも必要になりますので、
(workboxの場合は) fetchDidSucceed
のタイミングで最適化するコードを入れました。
Service Worker 以外の解決法
確認してませんが、Cloudflare Workers を利用して
上記の createPartialResponse 関数内と同様の処理を施せば対応可能かと思います。