Google Apps Scriptで転送システムや画像バイナリ表示を作りたかったが…そもそも無理だった

てことで、書きました。
できごと
自分のサーバがバレないURL転送が欲しくなった
noteに複数記事書いてると、最後に定型文とか書くよね?
そこに期間限定のメッセージとか載せたりするじゃない?
で思ったのだ。

と…
URL登録しておいて、画像を書き換えたらいいかも…とは思ったし、
PHPで作ろうと思えばカンタンだけど、
複数アカウント運営なので、PHPのURLや画像URLからサーバばれて、本垢バレるじゃん。
ウマくない。
じゃあ、例えばbit.lyとかの短縮サービスを使えば、元のURLは分からないし、使えば良いかなって思うじゃん?
でも後からURL変えられない。
これで画像は解決してないし。

という判断になった。
何がしたかったかまとめ(要件)
- 表形式でURLを管理したい ⇨ スプシ感覚でID・URL・画像などを一元管理
- スクリプトで処理分岐したい ⇨
?id=xxx&type=url
のようにURL間違えにくく - 公開URLがある ⇨ 外部からアクセス・表示・転送
- 無料で使える ⇨ コストゼロは必須
- 別々のURLで管理 ⇨ コピーで複数作れる
Google Apps Scriptで転送・画像読込システムを作ってみよう!
データ管理
スプレッドシートに以下のように登録
id | url | image |
---|---|---|
koudou | https://note.com/kuraeqooga | https://qooga.jb-jk.net/item/image/cover/qooga/2025/koudou-switch.png |
…以下略… | …以下略… | …以下略… |
idの値を『探索キー』として、データベースのように使う。
API
https://script.google.com/macros/s/なんとかかんとか/exec?id=【探索キー】&type=【urlかimage】
APIアクセス方法
…?id=【探索キー】&type=url
⇨ 302リダイレクト
…?id=【探索キー】&type=image
⇨ 画像バイナリ表示
Apps Scriptコード
function doGet(e) { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); const idParam = e.parameter.id; const typeParam = e.parameter.type; const idColumn = sheet.getRange(1, 1, sheet.getLastRow()).getValues().flat(); const rowIndex = idColumn.indexOf(idParam); if (rowIndex === -1) { return ContentService.createTextOutput("ID not found").setMimeType(ContentService.MimeType.TEXT); } const row = sheet.getRange(rowIndex + 1, 1, 1, 3).getValues()[0]; if (typeParam === "url") { const redirectUrl = row[1]; if (!redirectUrl || redirectUrl.trim() === "") { return ContentService.createTextOutput("Invalid URL").setMimeType(ContentService.MimeType.TEXT); } return HtmlService.createHtmlOutput(`<script>location.href='${redirectUrl}'</script>`); } if (typeParam === "image") { const imageUrl = row[2]; const response = UrlFetchApp.fetch(imageUrl); const blob = response.getBlob(); blob.setName("image.png"); // 任意のファイル名 return blob; } return ContentService.createTextOutput("Invalid type").setMimeType(ContentService.MimeType.TEXT); }
appsscript.json対応
設定されてないと、以下のメッセージが出る。
exception: urlfetchapp.fetch を呼び出す権限がありません。
『プロジェクトの設定』⇨『「appsscript.json」マニフェスト ファイルをエディタで表示する』をチェック
エディタに出来た『appsscript.json』に
"oauthScopes": [ "https://www.googleapis.com/auth/script.external_request", "https://www.googleapis.com/auth/spreadsheets" ]
を追加しておく。
デプロイして許可を忘れずに
「テストだけでいいやー」て場合でも、1回デプロイして許可しないと使えないから注意。
やりかたは割愛する。
結果
302リダイレクト
あ・・・
画像バイナリ表示
あ・・・

GASで作るとそうになっちゃうよね!
Google Apps Scriptには制約がある
GASには色々制約があるから、作れないものもあるのだ。
もう目に馴染んでて忘れてたけど、iFrameもその1つ。
GAS Webアプリの制約ポイント
おおよそこんな感じ
制約 | 詳細 |
---|---|
iframe表示 | GASのWebアプリはGoogleドメイン内でiframeタグに包まれる |
window.location.href でのリダイレクト |
iframeタグ内なので親ページには効かない。iFrame禁止になってるサイトなら読込禁止になる |
X-Frame-Options の制御 |
HtmlService.setXFrameOptionsMode() で一部制御可能ではあるが…制限あり |
外部埋め込み不可 | GASのWebアプリは他ドメインからの埋め込みを基本的に拒否する |
他にも画像読み込むのにクロスドメインだとか、GASで読込禁止だーだとかまぁつまり
作ろうと思った方の参考になればいいね!

もう『要件』を叶える方法はないの?
て言われると、そんなことはなくて、代わりになるものは存在する。
GASの代替になるスクリプト環境+公開URL対応サービス
調べるのめんどくさいからCopilotさんにお願いした。
間違ってたらごめんね。
サービス | 特徴 | 公開URL | 画像/リダイレクト対応 | 備考 |
---|---|---|---|---|
Firebase Hosting + Cloud Functions | JS/TSで自由にAPIとページ構築 | 独自URL可 | 完全制御可能 | Google製。GASより自由度高い |
Vercel / Netlify | HTML/JSをGit連携で即公開 | 独自ドメイン対応 | iframe制限なし | 静的サイト+APIもOK |
Glitch | ブラウザでNode.js開発可 | 即時公開 | Expressで自由制御 | 学習にも向いてる。無料枠あり |
Replit | Python/Nodeなど多言語対応 | Web公開可 | Webサーバ構築可能 | GASより柔軟。教育向けにも人気 |
Cloudflare Pages + Workers | 高速CDN+JSベースAPI | 高速公開 | リダイレクト・画像制御OK | 軽量で爆速。無料枠も強い |
管理方法 | 表形式 | スクリプト制御 | 公開URL | 無料枠 | テンプレート化 |
---|---|---|---|---|---|
GAS(制限あり) | ✅ | ✅ | ⚠️ iframe制限 | ✅ | ✅ |
Notion + Vercel(またはReplit) | ✅ | ✅ | ✅ | ✅ | ✅ |
Airtable + Workers | ✅ | ✅ | ✅ | ✅ | ✅ |
Firebase + スプレッドシート | ✅ | ✅ | ✅ | ✅ | ✅(やや重) |

けど…いつやろうかな…
Vercelの公開URLについて
- デフォルトURL ⇨
https://your-project-name.vercel.app
(無料で発行) - 複製時のURL ⇨ プロジェクト名が違えば `your-copy.vercel.app` など別URLになる
- サブドメイン運用 ⇨
client1.vercel.app
、client2.vercel.app
のように分けられる - 独自ドメイン ⇨ 任意。使いたければ設定可能(無料枠でもOK)
コメント