接獲使用者通報才知 Edge 跟 Chrome 有個我沒用過的功能 - 「複製索引標籤」(Edge,下圖左)/「複製」分頁 (Chrome,下圖右)。

實測複製分頁會沿用相同 HTML 原始碼,欄位填寫內容也會被一起帶入新分頁,程式若未考慮此種操作情境,可能引發問題。

用以下 ASP.NET MVC 網頁重現問題,網頁有三個值,一個由 Razor 語法在伺服器端產生,一個為 JavaScript 動態生成,一個由使用者輸入:

@{
    ViewData["Title"] = "Home";
}
<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8" />   
    <style>
        body {
            margin: 10px;
            font-size: 11pt;
        }
        a {
            font-size: 12pt;
            margin-left: 12px;
            color: dodgerblue;
            &:visited {
                color: dodgerblue;
            }
        }
        table {
            border-collapse: collapse;
            td {
                border: 1px solid gray;
                padding: 5px 10px;
            }
            td:first-child {
                background-color: lightgray;
                text-align: right;
            }
            input {
                width: 100%;
                padding: 5px;
                box-sizing: border-box;
            }            
        }

    </style>
</head>
<body>
<h2>
    「複製索引標籤」測試
    <a href="" target="_blank">在新分頁開啟</a>
</h2>

<table>
    <tr>
        <td>Razor 值</td>
        <td><span id="razorValue">@Guid.NewGuid().ToString()</span></td>
    </tr>
    <tr>
        <td>JavaScript 值</td>
        <td><span id="jsValue"></span></td>
    </tr>
    <tr>
        <td>輸入欄位</td>
        <td><input type="text" name="inputField" placeholder="Type somthing here..." /></td>
    </tr>
</table>
<script>
    const jsValue = Math.random().toString(16).substring(2);
    document.getElementById("jsValue").innerText = jsValue;
</script>
</body>
</html>

<a href="" target="_blank"> 在新分頁開啟,三個值都會重新產生或等待輸入:

若使用複製分頁方式,可發現 Razor 值(伺服器端產生)及使用者輸入內容相同,僅 JavaScript 值會在每次顯示網頁時重新產生而不同:

若兩個分頁使用重複的伺服端生成值會導致問題(例如:該是唯一 GUID 值,不應從兩個分頁重複送出),有沒有辦法偵測這種複製分頁行為呢?

我想到一個簡單做法,借用 Broadcast Channel API,以 GUID 或唯一值作為頻道名詞廣播,若有另一個分頁使用相同 GUID 接收到廣播訊息,就代表有兩個分頁使用相同 GUID,視需求決定處置方式,例如:彈出警告、阻擋送出表單或禁止網頁操作... 等。

<script>
    const uniqueId = document.getElementById("razorValue").innerText;
    const channel = new BroadcastChannel(uniqueId);
    // 正常情況不該收到來自此唯一值的廣播,若有代表初四了
    channel.addEventListener("message", (event) => {
        if (event.data === uniqueId) {
            alert("偵測到重複分頁");
        }
    });
    // 對唯一值頻道送出訊息
    channel.postMessage(uniqueId);
</script>

測試成功。

Highlights Edge/Chrome “duplicate tab” behavior, showing how server-generated values and user inputs persist across duplicated tabs. Demonstrates risks with non-unique server IDs and proposes detecting duplicates using the Broadcast Channel API.


Comments

Be the first to post a comment

Post a comment