YouTube 支援在網頁內嵌 IFrame,讓你可在自家網頁直接播放 YouTube 影片,我的部落格文章有時也會用。

thumbnail

最近幫忙查了一起案例,某些 YouTube 影片無法在某些網頁內嵌播放,必須單獨在 YouTube 開啟才能看。只有某些影片不能播,而且相同的網頁可能放在 A 網站 OK,放在 B 網站不行。

用以下 HTML 重現問題。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>YouTube Embedded Player</title>
</head>
<body>
  <iframe src="https://www.youtube.com/embed/K1uuK4QdvGY"></iframe>
</body>
</html>

網頁放到 JSBin 可內嵌播放。

存成本機檔案用瀏覽器開啟不行。

用 VSCode Live Server 不行。

掛到本機 IIS 又可以。

本機 IIS 但不用 locahost 改用 127.0.0.1 則又不行。

這堆測試結果搞到我都暈了,摸不到頭緒。事情的轉機在於:我做了一個實驗,把原本可正常內嵌播放的 localhost:80 用 devtunnel 導成對外 HTTPS,影片就不能播放了。同時有正常版跟異常版活體就好辦了,問題八成為網站送出的 HTTP Header 有關,對照 devtunnels 與本機 IIS 送出的 Header,經交叉比對並用 ASPX 模擬,我找到關鍵 - devtunnel 的回應包含 Referrer-Policy: same-origin 而原本 IIS 沒有,這是無法內嵌播放的關鍵:

用以下 ASPX 程式可重現問題:

<%@ Page Language="C#" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
    Response.Headers.Add("Referrer-Policy", "same-origin");
}
</script>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <title>Embedded YouTube Video</title>
</head>
<body>
        <iframe src="https://www.youtube.com/embed/K1uuK4QdvGY"></iframe> 
</body>
</html>

以上程式加了 Response.Headers.Add("Referrer-Policy", "same-origin"); 會無法播放,拿掉便正常,反覆驗證後,確認這是問題根源無誤。

有了關鍵字,很快找到相關文件及解法。比較完整的是這篇:Youtube iframe 嵌入錯誤: 「無法播放影片 在 YouTube 上觀看」 by 琳的備忘手札

簡單總結:

  1. 有音樂版權宣告的 YouTube 影片需要正確傳送 Referrer (至少要有 origin) 才能在 IFrame 內嵌播放,這解釋了為什麼問題只發生在特定影片跟特定網站(設了 Referrer-Policy 禁發 Referrer)
  2. 內嵌頁面必須對外公開(YouTube 可存取得到,localhost 是特例),且 Domain 不可以是 IP
  3. 我們可透過 <meta name="referrer" content="strict-origin-when-cross-origin" />IFrame 的 referrerpolicy 屬性 覆寫 HTTP Header 設定
  4. Referrer Policy 有以下選項,說明如下:(感謝 GPT 提供)
    • no-referrer
      不發送任何 Referer 資訊,隱私保護最大化
    • no-referrer-when-downgrade
      從 HTTPS 網站請求 HTTP 資源時不發送 Referer,其他情況下發送完整的 Referer。瀏覽器的預設值,適用於大多數情況
    • same-origin
      對同一來源(域名)內部請求發送 Referer,跨來源請求不發送。保護跨來源請求隱私,但允許內部來源間共享 Referer 資訊
    • origin
      發送來源基本資訊(不包含路徑),適用需要基本來源資訊但不需要詳細路徑資訊時
    • strict-origin
      發送來源的基本資訊,但僅 HTTPS 網站請求 HTTPS 資源時發送,從 HTTPS 請求 HTTP 資源時不發送。適用需要在 HTTPS 連接中保護隱私,但允許同等安全層級的來源資訊共享
    • origin-when-cross-origin
      相同來源時發送完整的 Referer,跨來源請求只發送來源基本資訊。適用在跨來源請求中隱藏詳細資訊,但允許內部來源的詳細資訊共享
    • strict-origin-when-cross-origin
      相同來源請求發送完整 Referer,跨來源 HTTPS 請求發送來源基本資訊,HTTPS 請求 HTTP 資源則不發送任何資訊。適用最高級別的隱私保護,確保從安全來源到非安全來源不發送任何資訊
    • unsafe-url
      無論何種請求都發送完整的 Referer,包括 URL 的整個路徑,不建議使用。

因此,本案例只需改寫成 <iframe src="https://www.youtube.com/embed/K1uuK4QdvGY" referrerpolicy="no-referrer-when-downgrade"></iframe> 應該就能過關了。我則學到一些 HTML 新知識。

Some YouTube videos may not play in embedded iframes due to Referrer-Policy settings. Specifically, the “same-origin” policy can block playback. Solutions include adjusting the referrer policy using meta tags or iframe attributes.


Comments

Be the first to post a comment

Post a comment