質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

2155閲覧

GASのウェブアプリケーションをjsのfetchで実行する方法

k.a_teratail

総合スコア845

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2022/03/28 14:32

編集2022/03/31 00:53

前提

GASを使用
ウェブアプリケーションのデプロイ設定を下記で行いました。

・次のユーザーとして実行
ウェブアプリケーションにアクセスしているユーザ

・アクセスできるユーザ
組織 内の全員

実現したいこと

htmlファイルに記載したjavascriptから、デプロイを行なったGASの結果を取得したです。

また、実行・アクセスできるユーザは組織内のユーザのみに限定したいので、
GASデプロイ設定の「次のユーザーとして実行」と「アクセスできるユーザ」は上記の設定でお願いしたいです。

発生している問題・エラーメッセージ

上記の設定にすると処理結果を受け取れてません。

chromeのコンソールで確認するとこのような中身になってました。

console

1Response {type: 'opaque', url: '', redirected: false, status: 0, ok: false, …} 2body: (...) 3bodyUsed: false 4headers: Headers {} 5ok: false 6redirected: false 7status: 0 8statusText: "" 9type: "opaque" 10url: "" 11[[Prototype]]: Response 12 13戻り値:

該当のソースコード

GASのコード

gs

1function doGet(e) { 2 3 let json = { 4 'text': 'aaaa' 5 } 6 let res = JSON.stringify(json) 7 return ContentService.createTextOutput(res).setMimeType(ContentService.MimeType.TEXT) 8}

HTMLのコード

html

1<!DOCTYPE html> 2<html> 3 <head> 4 <meta charset="utf-8" /> 5 </head> 6 <body> 7 </body> 8 <script> 9 let url = 'https://script.google.com/macros/s/****/exec'; 10 11 let option = { 12 'mode': 'no-cors' 13 , 'method': 'GET' 14 , 'Content-Type': 'text/plain' 15 }; 16 17 let text = ''; 18 fetch(url, option) 19 .then( 20 function(res) { 21 console.log(res); 22 return res.text(); 23 } 24 ).then( 25 function(json) { 26 text = json; 27 console.log("戻り値:" + json); 28 } 29 ).catch(function(exception) { 30 console.log(exception); 31 }); 32 </script> 33</html>

試したこと

GASのデプロイ設定を下記のようにすると問題ないことは確認できました。

・次のユーザーとして実行
自分

・アクセスできるユーザ
全員

HTMLに記載のoption変数を下記に変更

js

1 let option = { 2 'method': 'GET' 3 , 'Content-Type': 'text/plain' 4 };

chromeのコンソール

Response {type: 'cors', url: 'https://script.googleusercontent.com/macros/echo?u…mZixddpbUVg&lib=Mv9wYkUhvGHhGDLT7HCgnKd1sAI6oo1Au', redirected: true, status: 200, ok: true, …} body: (...) bodyUsed: true headers: Headers {} ok: true redirected: true status: 200 statusText: "" type: "cors" url: "https://script.googleusercontent.com/macros/echo?user_content_key=t6AwjjspV1kU-_1qlO63Z70XrFMres0fI6ZSpURhXch6TbNOgrYKmA3bFlVl5B6MYfaE8wqe2DRC_OgKWl0SejQeQtPVB4Pgm5_BxDlH2jW0nuo2oDemN9CCS2h10ox_1xSncGQajx_ryfhECjZEnPBIAyb9Xw1qqs9Rjqalb0gct2gCt1kEk1G9y721k1e5r_xTxoPnJWNKJQ7J6HlSX7MjKYTMKDczKxY3e265L2RmZixddpbUVg&lib=Mv9wYkUhvGHhGDLT7HCgnKd1sAI6oo1Au" [[Prototype]]: Response 戻り値:{"text":"aaaa"}

しかし、この設定だと
Urlを知っていると誰でも実行可能で危険
なのでこの設定は避けたいです。

画像

credentials: 'include'credentials: 'same-origin'credentials: 'omit'
イメージ説明イメージ説明イメージ説明

ScriptApp.getOAuthToken() で値を取得し
HTMLファイルに反映させましたが、結果は変わらずでした。

ScriptApp.getOAuthToken()の値を取得し、設定した方法

  1. ダミー関数をGASのエディタから実行して、コンソールに表示された値をコピー
  2. 1 でコピーした値をHTMLファイルの oAuthToken の値にセット

gs

1// ダミー関数 2function myFunction() { 3 console.log(ScriptApp.getOAuthToken()) 4} 5

GASでのスコープ設定

json

1 "oauthScopes": [ 2 "https://www.googleapis.com/auth/script.external_request", 3 "https://www.googleapis.com/auth/userinfo.email", 4 "https://www.googleapis.com/auth/drive.file", 5 "https://www.googleapis.com/auth/drive", 6 "https://www.googleapis.com/auth/drive.apps.readonly", 7 "https://www.googleapis.com/auth/drive.readonly", 8 "https://www.googleapis.com/auth/drive.appfolder", 9 "https://www.googleapis.com/auth/drive.scripts" 10 ]

html

1<!DOCTYPE html> 2<html> 3 <head> 4 <meta charset="utf-8" /> 5 </head> 6 <body> 7 </body> 8 <script> 9 let url = 'https://script.google.com/macros/s/***/exec'; 10 11 let oAuthToken = 'ya29.A0ARrdaM-b4Qkdt970ib90xUfoXIsCqkJYZWyg1KnJw04kIBlFvSZ1QwaP-u_ed5BbIamgpT6p-MWqYPoY5RtMWvXXt06DqmeIE6C2cromOec2WSlY4wQanAvAhLpoGAoZKf80377UACfIuoAGLqV8ks8X-MVpnKn5DO7icpB6KxSfhDI'; 12 13 let option = { 14 'mode': 'no-cors' 15 , 'method': 'GET' 16 , 'Content-Type': 'text/plain' 17 , 'headers': { 18 "Authorization": "Bearer " + oAuthToken 19 } 20 }; 21 22 let text = ''; 23 fetch(url, option) 24 .then( 25 function(res) { 26 console.log(res); 27 return res.text(); 28 } 29 ).then( 30 function(json) { 31 text = json; 32 console.log("戻り値:" + json); 33 } 34 ).catch(function(exception) { 35 console.log(exception); 36 }); 37 </script> 38</html>

画像の説明をここに入力

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

自己解決

自己解決しました。

  • Google OAuth 2.0 認証を使用したログイン
  • GCPのOAuth同意画面、認証情報のAPIキーとOAuth 2.0 クライアント IDの作成
  • GAS側で実行可能APIを使用

上記をすることでjsのfetchから実行できることを確認しました。

実装したコードは以下になります。

index.html

html

1<!doctype html> 2<html lang="ja"> 3 4<head> 5 <meta charset="UTF-8"> 6</head> 7 8<body> 9 <div id="auth-div" style="display: none;"> 10 <span>アカウント認証していないので、認証ボタンを表示する</span> 11 <button id="auth-btn" onclick="handleAuthClick(event)">認証</button> 12 </div> 13 <div id="exec-div" style="display: none;"> 14 <span>アカウント認証が問題無いので、実行ボタンを表示する</span> 15 <button id="exec-btn" onclick="execution(event)">実行</button> 16 <div> 17 実行結果: <label id="exec-result"></label> 18 </div> 19 </div> 20 <script defer src="https://apis.google.com/js/api.js" 21 onload="this.onload=function(){};handleClientLoad()" onreadystatechange="if (this.readyState === 'complete') this.onload()"></script> 22 <script src="index.js"></script> 23</body> 24</html>

index.js

js

1 2var CLIENT_ID = 'GCPの認証情報 Auth 2.0のクライアントID'; 3 4var API_KEY = 'GCPの認証情報 APIキー'; 5 6var SCOPES = [ 7 'https://www.googleapis.com/auth/userinfo.email' 8 , 'https://www.googleapis.com/auth/script.external_request' 9]; 10 11var SCRIPT_ID = 'GASの実行可能APIにある、/exec前のID'; 12 13var DISCOVERY_DOCS = [ 14 "https://script.googleapis.com/$discovery/rest?version=v1" 15]; 16 17// 認証用div 18var authDiv = document.getElementById('auth-div'); 19// 実行用div 20var execDiv = document.getElementById('exec-div'); 21 22// アクセス時に実行 23function handleClientLoad() { 24 gapi.load('client:auth2', initClient); 25} 26 27// 初期化処理 28function initClient() { 29 // GoogleAPIの初期化 30 gapi.client.init( 31 { 32 apiKey: API_KEY 33 , discoveryDocs: DISCOVERY_DOCS 34 , clientId: CLIENT_ID 35 , scope: SCOPES.join(' ') 36 } 37 ).then(function () { 38 // ログイン状態取得 39 let isSignIn = gapi.auth2.getAuthInstance().isSignedIn.get(); 40 41 if (isSignIn) { 42 // ログイン済みなら、実行用の項目表示 43 execDisplay(); 44 } else { 45 // 未ログインなら、ログイン用の項目表示 46 loginDisplay(); 47 } 48 }, function (error) { 49 console.log("エラー: " + error); 50 }); 51} 52 53// ログイン用の項目表示 54function loginDisplay() { 55 // 未ログイン 56 authDiv.style.display = 'inline'; 57 execDiv.style.display = 'none'; 58} 59 60// 実行用の項目表示 61function execDisplay() { 62 // ログイン済み 63 authDiv.style.display = 'none'; 64 execDiv.style.display = 'inline'; 65} 66 67 68// 認証ボタンクリック時 69function handleAuthClick(event) { 70 gapi.auth2.getAuthInstance().signIn() 71 .then(function (res) { 72 // ログイン認証成功 73 execDisplay(); 74 }, function (error) { 75 // ログイン認証失敗 76 console.log("ログイン認証失敗: " + JSON.stringify(error, null, 2)); 77 }); 78} 79 80// 実行ボタンクリック時 81function execution(event) { 82 83 let request = { 84 'function': 'exec' 85 , 'parameters': [] 86 }; 87 88 let op = gapi.client.request( 89 { 90 'root': 'https://script.googleapis.com' 91 , 'path': 'v1/scripts/' + SCRIPT_ID + ':run' 92 , 'method': 'POST' 93 , 'body': request 94 } 95 ); 96 97 op.execute(function (res) { 98 // console.log("実行結果: " + JSON.stringify(res, null, 2)); 99 100 if (res.error) { 101 // エラーがある場合 102 if (res.error.status) { 103 console.log('API実行エラー: ' + JSON.stringify(res, null, 4)); 104 } else { 105 // スクリプトエラーの場合 106 let error = res.error.details[0]; 107 console.log('スクリプトエラー: ' + error.errorMessage); 108 } 109 } else { 110 let json = JSON.parse(res.response.result); 111 // console.log(json); 112 113 // 実行結果表示ラベル 114 let execLabel = document.getElementById('exec-result'); 115 116 if (json.result === 'ok') { 117 execLabel.innerText = '' + '\r\n'; 118 execLabel.innerText += '正常終了しました。'; 119 } else { 120 execLabel.innerText = '処理エラー'; 121 } 122 } 123 }); 124}

index.gs

gs

1function exec() { 2 let res = { 3 "test": 123 4 } 5 let json = res 6 return JSON.stringify(json) 7}

index.html表示すると
未ログインの時は、「認証ボタン」が表示されます。
ログイン済みの時は、「実行ボタン」が表示されます。

「実行ボタン」をクリックすると、問題ない場合は「実行結果: 正常終了しました。」が表示されます。

投稿2022/04/11 05:36

編集2022/04/21 03:31
k.a_teratail

総合スコア845

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

認証情報が送信されないので、組織外と判断されているのではないでしょうか。

たとえば、認証情報つきのリクエストの送信 のように認証情報を送信して実行するとどうなるでしょうか。

投稿2022/03/28 15:13

CHERRY

総合スコア25171

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

k.a_teratail

2022/03/29 00:59 編集

回答ありがとうございます。 fetchのinit引数に追加して実行しましたが、結果は変わらずでした。 こちらで画像は追加できないので、本文の方に実施結果画像を追加しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問