友達に言われて、こんな感じの実装もありじゃね?という感じのノリで書いている記事です。
制約
この実装を使う場合、以下の制約を守らないと上手く動かないと思います。
- 開くページに遷移がないこと(リンクを踏んで別のページに移動しないこと)
- 開くページが同じドメイン内であるか、クロスオリジンOKなこと
- 同じHTTPS/HTTPプロトコルで通信していること
実装
URL非表示のページを開くテスト
<button id='btn'>開く</button>
<script>
// 開くボタンが押されたら
document.getElementById('btn').onclick = () => {
fetch('/supersecret.html', {method: 'GET'})
.then(data => data.text())
.then(res => {
// ウィンドウを作成する
let w = window.open('','_blank', 'popup=1');
// 初期状態としてHTMLを直接挿入
w.document.body.innerHTML = res
// ページがリロードされた時のハンドラー
const resetHandler = () => {
w.addEventListener('beforeunload', () => {
// もしリロードされたら、0.1秒待ってHTMLを挿入しハンドラーをリセットする
setTimeout(() => {
try{
w.document.body.innerHTML = res;
} catch(err){
// クロスオリジンでエラー(URLバーが直接編集されたような場合)は、windowを閉じる
w.close();
}
resetHandler();
}, 100);
});
}
resetHandler();
})
}
</script>
デモ:https://165cmtallboy.github.io/secret-window/
解説
fetchで生のHTMLを直接取得し、そのデータをwindow.body.innerHTMLを通して直接ウィンドウに書き込んでいます。
ページ自体を読み込ませているさせているわけではないので、ブラウザ上のURLバーにはURLが表示されません。
サンプルコード
そのままWebサーバに置けば動きます
注意
ウェブ触ったことある人なら瞬殺でURL取られると思います。
絶対に他の人にURLを渡されたくない、ワンタイムなページを提供したい場合は
リンクに識別のためのパラメータをつけておいて、一度使われたパラメータには2度と見せないとかサーバー側の実装をしないと行けないと思います。
GET: /secretpage?token=929829503201
一度アクセスがあったトークン(929829503201)には403 Forbiddenを返す。みたいな