🎉

Google Apps ScriptのWebアプリをiframeに埋め込む方法

2023/01/13に公開
10

埋め込みできない・・・

Google Apps Scriptで作成したWebアプリケーションはデフォルトだとiframeに埋め込むことができません。
これはレスポンスヘッダーのX-Frame-OptionsSAMEORIGINが設定されている為です。

この状態だと埋め込みエラーが表示される・・・

setXFrameOptionsModeを設定しよう

HtmlServicesetXFrameOptionsModeメソッドにXFrameOptionsModeを渡すことで、X-Frame-Optionsの値を変更できます。
XFrameOptionsMode.ALLOWALLを指定してみましょう。

function doGet() {
  let html = HtmlService
    .createHtmlOutputFromFile('index')
    .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
  return html;
}

templateを使っている場合もevaluate()実行後に同様の設定が可能です。

function doGet() {
  let template = HtmlService.createTemplateFromFile("index");

  template.tite = 'タイトル';

  return template
    .evaluate()
    .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}

再デプロイとレスポンスヘッダーの確認

再デプロイ後、レスポンスヘッダーを確認するとX-Frame-Optionsが無くなっています。

埋め込み再挑戦

このWebアプリを再度iframeで埋め込むと・・・
無事に表示することができました。

SARAH Tech Blog

Discussion

ぺんぎん@自作PCぺんぎん@自作PC

なんか…できません…。

function doGet(e) {
var re = HtmlService.createTemplateFromFile("index");
//メッセージを追加
re.version = "1.20.1";
return re.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME).setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL).addMetaTag("viewport","width=device-width,initial-scale=1").setFaviconUrl("https://upload.wikimedia.org/wikipedia/commons/6/68/Firefox_Developer_Edition_logo%2C_2017.png").addMetaTag("apple-mobile-web-app-capable","yes").addMetaTag("mobile-web-app-capable","yes");
}

LilycatLilycat

iframeのsrcに設定しているURLが「デプロイをテスト」で発行されるテスト用のURLになっていませんか?(末尾がdevで終わる)
本記事の設定を反映させるには正式なデプロイを行い、末尾がexecのURLを使ってみてください。

記事内の表現が分かりづらかったので、追記させていただきました!

takumitakumitakumitakumi

本記事のおかげで外部親HTMLのiframe内にGASで作成したwebアプリHTMLを追加させることが出来ました!

GAS-webアプリは簡単な発注画面のような作りで
① index.html →
② confirm.html →
③ complete.html
大まかにこのような作り~画面遷移になっています。

GAS-webアプリ単体では動作確認OKなのですが、
iframe内で動作させてみると ① index.html でボタンクリックした時に、
② confirm.html がブラウザ全体で画面遷移してしまい親HTMLから外れてしまいます。

親HTMLはそのままで、iframe内のみで GAS-webアプリの動作を継続させる方法はありますでしょうか?

LilycatLilycat

お役に立てたようで良かったです!

ご質問の件ですが、具体的にどのような方法で画面遷移されてますか?
遷移方法を変えることで、親ウィンドウへの影響を抑えられるかもしれません。

takumitakumitakumitakumi

返信ありがとうございます!

GASおじさんのブログ
https://uncle-gas.com/gas-html-order-form/
上記サイトの「発注フォームを作る」を参考に(ほぼ丸々コピペ)で作成しました。

doGet(e) と doPost(e) の一部コードは下記の通りです。

function doGet(e) {
const items = getAllRecords('商品');
const template = HtmlService.createTemplateFromFile('index');
template.deployURL = ScriptApp.getService().getUrl();
template.formHTML = getFormHTML(e, items);
const htmlOutput = template.evaluate();
htmlOutput.addMetaTag('viewport', 'width=device-width, initial-scale=1');
htmlOutput.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
return htmlOutput;
}

function doPost(e) {
const items = getAllRecords('商品');
// index.htmlで「確認画面へ」ボタンが押されたらconfirm.htmlへ
if(e.parameter.confirm) {
const template = HtmlService.createTemplateFromFile('confirm');
template.deployURL = ScriptApp.getService().getUrl();
template.confirmHTML = getConfirmHTML(e, items);
const htmlOutput = template.evaluate();
htmlOutput.addMetaTag('viewport', 'width=device-width, initial-scale=1');
htmlOutput.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
return htmlOutput;
}

// confirm.htmlで「発注する」ボタンが押されたらcomplete.htmlへ
if(e.parameter.submit) {
createOrder(e, items);
//updateZaiko(e, items);
sendMail(e, items);
const template = HtmlService.createTemplateFromFile('complete');
template.deployURL = ScriptApp.getService().getUrl();
const htmlOutput = template.evaluate();
htmlOutput.addMetaTag('viewport', 'width=device-width, initial-scale=1');
htmlOutput.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
return htmlOutput;
}
}

doGetのみではなく、doPostにもsetXFrameOptions~を記述すればいいのかな?
と、素人判断で追記していますが希望の動作になりません(iframe内でページ遷移せずに親ページを遷移してしまいます)

そもそも不可能なのか、または何かヒントを頂ければ幸いです!

LilycatLilycat

index.htmlとconfirm.htmlのformタグに、target="_self" を追加してみてください!

+ <form class="mb-5" method="POST" action="<?= deployURL ?>" target="_self">
- <form class="mb-5" method="POST" action="<?= deployURL ?>" >
takumitakumitakumitakumi

早速追加してみました!

結果は
① index.html →
② confirm.html は iframe内で希望通りに動作しました!(歓喜)

② confirm.html →
③ complete.html は 画面真っ白となりました。

iframe内からではく、GAS‐HTML親ブラウザでテストしても 真っ白となりました。
② confirm.html内の target="_self" を取り除いてみると、元通りに ③ complete.html が正常に表示されました。

最後の ③ complete.html で トップへ戻るリンク<a href=~ にも target="_self" を追加してみてはおりますが、② → ③の時点で真っ白のため試せてはおりません。

なにか足りない部分があるのでしょうか...?

LilycatLilycat

私も同じ症状になることを確認しました。
どうやら2回目の遷移のときにこの事象が起きるようです。
index -> confirm -> conplete だけでなく、
index -> 1回目入力エラー -> 2回目入力エラーでも2回目入力エラーは画面表示されませんでした。
GASでのiframe内のpost遷移になにか問題があるようで、解決方法はまだわかっておりません。

追加の開発が必要になりますが、postで遷移させるのではなく、スクリプトによってSPAライクな動作に変更すれば解決する可能性はあるかと思います。

takumitakumitakumitakumi

Lilycat様

事象再現いただきありがとうございました。
SPAライク=単一webページ設計構造のようにということですね(ググってみました)
引き続きいろいろ調べて勉強してみます!