新分頁或 iframe
新分頁讓桌面用整個視窗。iframe 是你網頁裡的一個框,讓桌面留在你的網頁裡。
| 新分頁 | iframe | |
|---|---|---|
| Anping 伺服器上的設定 | 不用 | 把你網站的網址加進 Oturl:FrameAncestors |
| Win、Alt+Tab | 全螢幕(Chrome、Edge)或 Keys | Keys(框裡攔不到這些按鍵) |
| Ctrl+Alt+Del | Keys | Keys |
| 重新整理 | 一段時間內會重新連線(重新連線視窗) | 瀏覽器還記得這個連結時會重新連線(下方) |
新分頁
在使用者點擊的當下先開分頁,再向你的伺服器要連結。晚一點才開的新視窗,瀏覽器會當成彈出式視窗擋掉。
button.addEventListener('click', async () => {
const tab = window.open('', '_blank') // during the click
if (tab) tab.opener = null
const response = await fetch('/api/anping-link', { method: 'POST' })
const { url } = await response.json() // your server asks Anping
if (tab) tab.location.replace(url)
})你的網頁本身放在受限制的框(sandbox)裡?
那個框的 sandbox 屬性需要 allow-popups 和 allow-popups-to-escape-sandbox,否則新分頁會被擋,或繼續受 sandbox 限制。
iframe
<iframe src="https://anping.example.com/oturl.html?key=...&pass=..."
title="Remote desktop"
allow="fullscreen; clipboard-read; clipboard-write; autoplay"
referrerpolicy="no-referrer"
style="width: 100%; height: 80vh; border: 0"></iframe>allow 裡的項目 | 為什麼需要 |
|---|---|
fullscreen | 工具列的 Full screen 按鈕。 |
clipboard-read, clipboard-write | 瀏覽器允許時,複製貼上會自動處理;否則使用者用 Clipboard 面板。 |
autoplay | 在你的網頁點過之後聲音就能開始,不必在 iframe 裡點。更多沒有它的話,工具列會顯示 Enable sound,直到 iframe 裡的點擊或按鍵。 |
referrerpolicy="no-referrer" | 連結裡的機密部分(key 和 pass)永遠不會被送到別的網站。 |
resolution=fittobrowser 時,遠端畫面跟著框的大小。
允許你的網頁
只有連結頁面(/oturl.html)能放進框裡,而且只限你列出的網站。每個網站寫成 https:// 加主機名稱(和連接埠),不含路徑,或寫 'self'。
技術細節
Anping 以 Content-Security-Policy: frame-ancestors 送出這份清單。
Oturl__FrameAncestors__0=https://app.example.com
Oturl__FrameAncestors__1=https://portal.example.com在框裡重新整理
瀏覽器用一個小 cookie 記住這個連結。在 https 的框裡,每個放 Anping 的網站各有自己的一份(技術細節:SameSite=None; Secure; Partitioned)。
| 瀏覽器 | 重新整理你的網頁時 |
|---|---|
| Chrome、Edge(114 以後) | 會重新連線(已測試)。 |
| Firefox | 應該會重新連線;還沒完整測過。 |
| Safari | 會擋別的網站的 cookie,所以多半出現已使用的訊息。 |
| 純 http(開發) | 只有你的網頁在同一個網站時才行(技術細節:SameSite=Strict)。 |
cookie 被擋時;在負載平衡器後面時
- cookie 被擋的地方,頁面自己的 Reconnect 仍然可用(頁面開著時它自己留了一份);重新整理則會出現已使用的訊息,你的網頁需要新的連結。
- 在處理 https 的負載平衡器(TLS 代理)後面時,請設定
ForwardedHeaders:KnownNetworks,Anping 伺服器才知道頁面是經由 https 來的(設定)。
送給你網頁的訊息
框裡的頁面會告訴你的網頁發生了什麼事(用 postMessage)。只有 Oturl:FrameAncestors 列出的網站收得到。
- 桌面出現,每次重新連線後也會
- 連結已用過、過期或不存在
- 連線斷了:頁面自己重試
- 及時連回來
- 一分鐘內沒連回來(最終的錯誤:
ended) - Disconnect、遠端結束或錯誤
- 使用者按了 Reconnect
- 重新連線視窗過了
- End、閒置或時間上限、重新啟動、最終的錯誤:需要新的連結
window.addEventListener('message', (e) => {
if (e.origin !== 'https://anping.example.com' || e.data?.source !== 'anping' || e.data.v !== 1) return
// e.data.type: connected | reconnecting | disconnected | ended | link_invalid
})每則訊息長這樣:{source: 'anping', v: 1, type, link, code?, until?}。link 是連結的代碼:不是機密,跟連線記錄裡的一樣,Anping 給出之前是 null。v 是版本:只有欄位的意義改變或被拿掉時才會改。下表中,type 是發生了什麼,code 是原因,until 是頁面會試到什麼時候,或 Reconnect 可以用到什麼時候。
type | code | until |
|---|---|---|
connected | 無 | 無 |
reconnecting | connection_lost 或其他短暫的錯誤 | 停止重試的時間 |
disconnected | closed(按了 Disconnect,或遠端結束)或錯誤代碼 | 重新連線視窗結束的時間 |
ended | session_ended(使用者按了 End)、idle_timeout、max_duration、server_restart、其他錯誤代碼,或視窗過了之後的 disconnected 代碼 | 無 |
link_invalid | 無 | 無 |
聲音和自動播放
瀏覽器要等使用者互動後才允許聲音,所以連結的聲音(soundenabled=true)從第一次點擊或按鍵開始。在那之前工具列顯示 Enable sound,之後是 Mute 或 Unmute。用 iframe 時,請在 allow 加上 autoplay。
更多
之前送來的聲音會丟掉,所以之後不會一次全部播出來。