wvgw1692
@wvgw1692 (spwv)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

[GAS] WebアプリのdoPostにおけるURLの設定について

解決したいこと

GASでWebアプリを作成する際に、postの送信先をGASに設定するという説明をサイト上でよく見かけます。
htmlファイル上で<form method ="post" action="[デプロイしたWebアプリのURL]">と記述する感じです。
手順としては、

  1. Webアプリをデプロイする
  2. デプロイしたWebアプリのURLを<form method action...>に記述する
  3. Webアプリを実行する

という流れみたいです。
しかし、この方法だとデプロイした時点で<form method action...>上のURLは既に決定されており、デプロイした後に書き換えてもWebアプリには反映されない気がしています。
デプロイした時点で記述されていたURLにpostが送信されているはずです。

一応、一度デプロイしたURLを<form method action...>に記述し、再度デプロイを行うことでWebアプリとして想定した動作を実現することはできますが、効率的でないと思います。

デプロイする段階で、GAS自身にpostを送るための方法は何かないでしょうか?

0

質問の内容から、doPostの関数を含んだGoogle Apps Scriptと、表示されているHTML formを含んだHTMLが同一のGoogle Apps Script projectに含まれており、この状況下でHTML formからのデータをGoogle Apps Script側へ送ろうとしているのではないかと推測します。

この推測が正しいようであれば、下記の2つのパターンはいかがでしょうか。

パターン1

今の場合、method ="post" action="[デプロイしたWebアプリのURL]"を使用せずともgoogle.script.runでデータをGoogle Apps Script側へ送ることができます。このとき、もしもHTMLがdoGetで使用されているのでなければ、Web Appsを使用する必要はありません。HTMLがdoGetで使用されている場合でも、すべてのスクリプトを作成してからWeb Appsを一度だけデプロイするだけで問題ありません。

パターン2

例えば、doPostの関数を含んだGoogle Apps Scriptと、表示されているHTML formを含んだHTMLを別々のGoogle Apps Script projectに分けるのもありかと思いました。これにより、doPostを含んだGoogle Apps Script projectでデプロイした際のURLはそのままもう一方のGoogle Apps Script projectを使用できます。

Note

  • 最初の推測が間違っている場合は、これらのパターンは役に立たないかもしれません。その際は謝罪致します。

  • パターン3として、ScriptApp.getService().getUrl()が使えるのであれば、これを提案したかったのですが、今現在、これはまだ使用できないようです。https://issuetracker.google.com/issues/235862472

0Like

https://script.google.com/macros/s/***/exec***(デプロイID)が可変してしまう問題は回避方法があります。「新しいデプロイ」ではなく「デプロイを管理」から既存のデプロイIDを編集してそこから新バージョンを作れば良いのです。

もう一つの方法として、初っぱなのデプロイからURLが指定済みにするにはテンプレート化してScriptApp.getService().getUrl()を使えば良いのです。テンプレート化する場合、評価してからHtmlOutputを返さなければ成りません。

コードを書いておきますが、特に理由が無いのであれば前者の方法が一番良いでしょう。
検証コードなのでここまで回りくどいコードを書く必要ありません。

Main.gs
class Main {
  static getHtmlOutput(e, filename = 'index.html') {
    Logger.log(e);

    this.requestMethod = e.method;

    const template = HtmlService.createTemplateFromFile(filename);
    const htmlOutput = template.evaluate();//コードの評価
    htmlOutput.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.DEFAULT);

    return htmlOutput;
  }

  static getRequestMethod() {
    return this.requestMethod;
  }
}

function doGet(e) {
  e['method'] = 'get';
  return Main.getHtmlOutput(e);
}

function doPost(e) {
  e['method'] = 'post';
  return Main.getHtmlOutput(e);
}
index.html
<!DOCTYPE html>
<html lang="ja">
	<head>
		<meta charset="UTF-8">
		<title>index</title>
		<base target="_top">
		<style></style>
		<script>
window.document.addEventListener('DOMContentLoaded', () => {
  new class {

    #gasMap = new Map();

    constructor() {
      this.#gasMap.set('url', '<?!= ScriptApp.getService().getUrl() ?>');
      this.#gasMap.set('method', '<?= Main.getRequestMethod() ?>');

      this.init();
    }

    init() {
      const inputForm = window.document.getElementById('inputForm');
      inputForm.action = this.#gasMap.get('url');

      const requestMethod = this.#gasMap.get('method');
      const info1 = window.document.getElementById('info1');
      info1.textContent = `このスクリプトのアドレスは ${this.#gasMap.get('url')} です。${(requestMethod === 'post') ? 'doPost' : 'doGet'} からコールされました。`;
    }
  }
});
		</script>
	</head>
	<body>
		<form id="inputForm" method="POST">
			<input type="hidden" name="test" value="1">
			<button type="submit">SUBMIT</button>
		</form>
		<p id="info1"></p>
	</body>
</html>

検証用Apps Script

tanaikeさんが指摘されている問題は、テンプレート内では問題なく実行できているのでこのコードは一応有効です。

0Like

Your answer might help someone💌