回答編集履歴
19
test
CHANGED
@@ -39,8 +39,6 @@
|
|
39
39
|
function postToGAS() {
|
40
40
|
const postparam = {
|
41
41
|
method: 'POST',
|
42
|
-
accept: 'application/json',
|
43
|
-
'content-type': 'application/x-www-form-urlencoded',
|
44
42
|
body: JSON.stringify(sourceList),
|
45
43
|
};
|
46
44
|
|
@@ -122,7 +120,7 @@
|
|
122
120
|
|
123
121
|
では、「mode: 'no-cors'」無しで通したい場合どうすればいいか?
|
124
122
|
→ そもそも`content-type': 'application/json' ` を指定するとプリフライト・リクエストになってしまうことが問題でした。
|
125
|
-
したがって、リクエストがいわゆる単純リクエストになるように `content-type': 'application/
|
123
|
+
したがって、リクエストがいわゆる単純リクエストになるように `content-type': 'application/json'` を削除します。
|
126
124
|
|
127
125
|
|
128
126
|
### GASの修正
|
18
test
CHANGED
@@ -66,13 +66,13 @@
|
|
66
66
|
|
67
67
|
function doPost(e) {
|
68
68
|
try {
|
69
|
-
const res = doPostP
|
69
|
+
const res = doPostProxy(e);
|
70
70
|
return res;
|
71
71
|
} catch (err) {
|
72
72
|
return ContentService.createTextOutput(JSON.stringify({ result: err.stack}));
|
73
73
|
}
|
74
74
|
}
|
75
|
-
function doPostP
|
75
|
+
function doPostProxy(e) {
|
76
76
|
const reqParam = JSON.parse(e.postData.getDataAsString());
|
77
77
|
const sheetNo = parseInt(reqParam.sheetNo) || 1;
|
78
78
|
// シートの取得
|
@@ -164,7 +164,7 @@
|
|
164
164
|
// Postリクエスト処理中のエラーをトラップするため try ~ catch で囲む。
|
165
165
|
function doPost(e) {
|
166
166
|
try {
|
167
|
-
const res = doPostP
|
167
|
+
const res = doPostProxy(e);
|
168
168
|
return res;
|
169
169
|
} catch (err) {
|
170
170
|
// エラーのスタックを JSON 形式で返す。
|
@@ -173,7 +173,7 @@
|
|
173
173
|
}
|
174
174
|
|
175
175
|
// doPost 処理を代理で行う
|
176
|
-
function doPostP
|
176
|
+
function doPostProxy(e) {
|
177
177
|
// もともとの doPost の処理
|
178
178
|
// ....
|
179
179
|
|
17
test
CHANGED
@@ -149,14 +149,17 @@
|
|
149
149
|
|
150
150
|
|
151
151
|
##### ③ GASからの戻り値の設定
|
152
|
-
|
152
|
+
mode:'no-cors'を設定していない場合で単純リクエストの場合:
|
153
|
-
GAS のWebアプリ
|
153
|
+
GAS のWebアプリからの戻り値は
|
154
154
|
+ 正常終了の場合 → Access-Control-Allow-Origin * 付きでレスポンスが返ってくる
|
155
155
|
+ エラーが発生した場合 → Access-Control-Allow-Origin なしで返ってくる → CORS policy によりブロックされる
|
156
|
-
|
156
|
+
となります。
|
157
|
+
|
158
|
+
mode:'no-cors'を設定した場合:
|
157
|
-
|
159
|
+
GAS のWebアプリからの戻り値は、正常終了かエラーにかかわらず、opaque なレスポンスとなります。
|
158
|
-
|
160
|
+
|
159
|
-
GAS 内部で発生したエラー内容を捕捉したいのであれば、GAS 側で doPost 内の処理を丸ごと try ~ catch ブロックで囲み、例外処理の中でエラー内容を(正常に)返すようなギミックを使います。(同時にエラー内容をログシートに出力するようにしてもよいでしょう)
|
161
|
+
したがって、GAS 内部で発生したエラー内容を捕捉したいのであれば、GAS 側で doPost 内の処理を丸ごと try ~ catch ブロックで囲み、例外処理の中でエラー内容を(正常に)返すようなギミックを使います。(同時にエラー内容をログシートに出力するようにしてもよいでしょう)
|
162
|
+
|
160
163
|
```js
|
161
164
|
// Postリクエスト処理中のエラーをトラップするため try ~ catch で囲む。
|
162
165
|
function doPost(e) {
|
16
test
CHANGED
@@ -188,9 +188,9 @@
|
|
188
188
|
|
189
189
|
---
|
190
190
|
|
191
|
-
|
191
|
+
あまり推奨しませんが、'content-type': 'application/json', かつ mode: 'no-cors' を指定した場合、
|
192
192
|
GAS 側に一切バグがなければ、一応スプレッドシートに正常に書き込まれます。
|
193
|
-
ただし上述の通り、仮にその後コードを修正してエラーが発生した
|
193
|
+
ただし上述の通り、仮にその後GASのコードを修正してGAS内部でエラーが発生したとしても、クライアント側ではエラー内容がわからないため、try~catch で囲んでログシートにエラー内容を記録する / スクリプトをGCPと結びつけてGoogleコンソールでログを確認する等しない限り、デバッグに苦労することになるでしょう。
|
194
194
|
|
195
195
|
|
196
196
|
|
15
test
CHANGED
@@ -51,7 +51,6 @@
|
|
51
51
|
console.log(data.result);
|
52
52
|
}).catch(err=>{
|
53
53
|
console.log("Error!");
|
54
|
-
console.log(err.status, err);
|
55
54
|
});
|
56
55
|
</script>
|
57
56
|
</body>
|
@@ -187,6 +186,11 @@
|
|
187
186
|
グローバル変数で定義している sheet という変数が doPost内で上書きされており、このために期待する動作になっていません。
|
188
187
|
sheet はローカル変数とし、postJsonToSpreadSheet に引数として渡すようにすればよいでしょう。(修正後コード中の変数「targetSheet」参照)
|
189
188
|
|
189
|
+
---
|
190
|
+
|
191
|
+
全く推奨しませんが、'content-type': 'application/json', かつ mode: 'no-cors' を指定した場合、
|
192
|
+
GAS 側に一切バグがなければ、一応スプレッドシートに正常に書き込まれます。
|
193
|
+
ただし上述の通り、仮にその後コードを修正してエラーが発生した場合、エラー内容がわからないため、デバッグに苦労することになるでしょう。
|
190
194
|
|
191
195
|
|
192
196
|
|
14
test
CHANGED
@@ -109,7 +109,7 @@
|
|
109
109
|
### CORS周りについて
|
110
110
|
|
111
111
|
> ・fetchメソッドでPOSTする際に以下のエラーが出て、スプレッドシートに書き込みが出来ないようです。
|
112
|
-
元コードのように、`'content-type': 'application/json' `を指定すると、[プリフライト・リクエスト](https://developer.mozilla.org/ja/docs/Glossary/Preflight_request)になります。プリフライト・リクエストを処理するには、サーバーが
|
112
|
+
元コードのように、`'content-type': 'application/json' `を指定すると、[プリフライト・リクエスト](https://developer.mozilla.org/ja/docs/Glossary/Preflight_request)になります。プリフライト・リクエストを処理するには、サーバーが対応している必要がありますが、GAS は 非対応です。
|
113
113
|
このため (「mode: 'no-cors'」 がない状態で `'content-type': 'application/json' `を指定したリクエストを GAS に送った場合) GAS との通信は CORS policy によりブロックされます。
|
114
114
|
|
115
115
|
> ・postparamに「mode: 'no-cors'」を追加したところ、「成功」が表示されましたが、スプレッドシートに書き込まれませんでした。
|
@@ -123,7 +123,7 @@
|
|
123
123
|
|
124
124
|
では、「mode: 'no-cors'」無しで通したい場合どうすればいいか?
|
125
125
|
→ そもそも`content-type': 'application/json' ` を指定するとプリフライト・リクエストになってしまうことが問題でした。
|
126
|
-
したがって、
|
126
|
+
したがって、リクエストがいわゆる単純リクエストになるように `content-type': 'application/x-www-form-urlencoded'` を指定します。
|
127
127
|
|
128
128
|
|
129
129
|
### GASの修正
|
13
test
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
|
2
|
-
「・投稿内容すべてをjavascriptで一括でPOSTして、GASでスプレッドシートに書き込みたい」について
|
2
|
+
「・投稿内容すべてをjavascriptで一括でPOSTして、GASでスプレッドシートに書き込みたい」について、先に動作する回答例を示して、後半で解説します。
|
3
|
-
先に動作する回答例を示して、後半で解説します。(コメントやコードの大部分は、元質問のものを残しておりますのでご了承ください)
|
4
|
-
|
5
3
|
(2番目の「・投稿内容すべてをスプレッドシートから一括でGETして、リストに表示したい」については具体的なコードが質問に一切示されておらず要件が全く不明であるため、割愛します)
|
6
4
|
|
7
5
|
**<例>**
|
8
6
|
**クライアント側HTML** sample.html
|
9
|
-
(コ
|
7
|
+
(コードの一部は、元質問のものを残しております)
|
10
8
|
```html
|
11
9
|
<!DOCTYPE html>
|
12
10
|
<html lang="ja">
|
12
test
CHANGED
@@ -6,6 +6,7 @@
|
|
6
6
|
|
7
7
|
**<例>**
|
8
8
|
**クライアント側HTML** sample.html
|
9
|
+
(コメントやコードの大部分は、元質問のものを残しております)
|
9
10
|
```html
|
10
11
|
<!DOCTYPE html>
|
11
12
|
<html lang="ja">
|
@@ -60,6 +61,7 @@
|
|
60
61
|
```
|
61
62
|
|
62
63
|
**GAS側のスクリプト** code.gs
|
64
|
+
(コメントの大部分は、元質問のものを残しております)
|
63
65
|
```js
|
64
66
|
const sheet_id = '*******************************';
|
65
67
|
const sheet_name = 'シート1';
|
11
test
CHANGED
@@ -139,12 +139,12 @@
|
|
139
139
|
```
|
140
140
|
|
141
141
|
|
142
|
-
##### ② sourceList
|
142
|
+
##### ② クライアントから送るデータ(sourceList)に dataプロパティ がないにもかかわらず、GAS側 で data プロパティを読み取ろうとしている。
|
143
143
|
|
144
144
|
```js
|
145
145
|
var data = JSON.parse(reqParam.data);
|
146
146
|
```
|
147
|
-
この部分ですが、クライアントから送られてくる JSON には data プロパティがないにもかかわらず、dataを読み取ろうと
|
147
|
+
この部分ですが、クライアントから送られてくる JSON には data プロパティがないにもかかわらず、data を読み取ろうとしており、結果 reqParam.data は undefined になってしまいます。
|
148
148
|
→ sourceList のデータに data プロパティを付けるか、sourceList はそのままにして「.data」を削除します。
|
149
149
|
あと、①で parse 済みであれば、この部分のJSON.parse() も不要になります。
|
150
150
|
|
10
test
CHANGED
@@ -170,8 +170,13 @@
|
|
170
170
|
}
|
171
171
|
}
|
172
172
|
|
173
|
+
// doPost 処理を代理で行う
|
173
174
|
function doPostPloxy(e) {
|
174
175
|
// もともとの doPost の処理
|
176
|
+
// ....
|
177
|
+
|
178
|
+
// 正常終了のメッセージを返す
|
179
|
+
return ContentService.createTextOutput(JSON.stringify({ result: "post done"}));
|
175
180
|
}
|
176
181
|
```
|
177
182
|
|
9
test
CHANGED
@@ -116,8 +116,8 @@
|
|
116
116
|
|
117
117
|
「mode: 'no-cors'」に設定すると、たしかに CORS エラーは発生しませんが、レスポンスは [opaque](https://developer.mozilla.org/ja/docs/Web/API/Response/type#:~:text=opaque%3A%20%E3%82%AA%E3%83%AA%E3%82%B8%E3%83%B3%E9%96%93%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9%E3%81%B8%E3%81%AE%20%22no%2Dcors%20%22%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%81%AB%E5%AF%BE%E3%81%99%E3%82%8B%E3%83%AC%E3%82%B9%E3%83%9D%E3%83%B3%E3%82%B9%E3%80%82%20%E5%8E%B3%E3%81%97%E3%81%8F%E5%88%B6%E9%99%90%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82) となり、GAS から JSON を返しても無視されて、空っぽのデータが返ってきます。
|
118
118
|
|
119
|
-
つまり GAS 内部でエラーがあろうとなかろうと、no-cors にしていると空っぽのレスポンスがポツンと返ってくるわけで(エラー扱いにならないので fetch の .catch にもつかまりません)、上のコードで「成功」と表示されたからと言ってGAS側が正常
|
119
|
+
つまり GAS 内部でエラーがあろうとなかろうと、no-cors にしていると常に空っぽのレスポンスがポツンと返ってくるわけで(エラー扱いにならないので fetch の .catch にもつかまりません)、上のコードで「成功」と表示されたからと言ってGAS側の処理が正常に完了したとは限りません。
|
120
|
-
(実際、元コードは GAS 側のコードにいくつかエラーがあり、スプレッドシートへ正常書き込みが行われる前に終了しています。)
|
120
|
+
(実際、元コードは GAS 側のコードにいくつかエラーがあり、スプレッドシートへ正常書き込みが行われる前にエラーで終了しています。)
|
121
121
|
|
122
122
|
結論として、GAS から post後の正常メッセージ/エラーメッセージを、内容がわかる形で返そうとするならば「mode: 'no-cors'」は使えません。
|
123
123
|
|
8
test
CHANGED
@@ -117,6 +117,7 @@
|
|
117
117
|
「mode: 'no-cors'」に設定すると、たしかに CORS エラーは発生しませんが、レスポンスは [opaque](https://developer.mozilla.org/ja/docs/Web/API/Response/type#:~:text=opaque%3A%20%E3%82%AA%E3%83%AA%E3%82%B8%E3%83%B3%E9%96%93%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9%E3%81%B8%E3%81%AE%20%22no%2Dcors%20%22%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%81%AB%E5%AF%BE%E3%81%99%E3%82%8B%E3%83%AC%E3%82%B9%E3%83%9D%E3%83%B3%E3%82%B9%E3%80%82%20%E5%8E%B3%E3%81%97%E3%81%8F%E5%88%B6%E9%99%90%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82) となり、GAS から JSON を返しても無視されて、空っぽのデータが返ってきます。
|
118
118
|
|
119
119
|
つまり GAS 内部でエラーがあろうとなかろうと、no-cors にしていると空っぽのレスポンスがポツンと返ってくるわけで(エラー扱いにならないので fetch の .catch にもつかまりません)、上のコードで「成功」と表示されたからと言ってGAS側が正常であるとは限りません。
|
120
|
+
(実際、元コードは GAS 側のコードにいくつかエラーがあり、スプレッドシートへ正常書き込みが行われる前に終了しています。)
|
120
121
|
|
121
122
|
結論として、GAS から post後の正常メッセージ/エラーメッセージを、内容がわかる形で返そうとするならば「mode: 'no-cors'」は使えません。
|
122
123
|
|
7
test
CHANGED
@@ -109,12 +109,12 @@
|
|
109
109
|
### CORS周りについて
|
110
110
|
|
111
111
|
> ・fetchメソッドでPOSTする際に以下のエラーが出て、スプレッドシートに書き込みが出来ないようです。
|
112
|
-
元コードのように、`content-type': 'application/json' `を指定すると、プリフライト・リクエストになる
|
112
|
+
元コードのように、`'content-type': 'application/json' `を指定すると、[プリフライト・リクエスト](https://developer.mozilla.org/ja/docs/Glossary/Preflight_request)になります。プリフライト・リクエストを処理するには、サーバーが OPTIONS リクエストに対応している必要がありますが、GAS は 対応していません。
|
113
|
+
このため (「mode: 'no-cors'」 がない状態で `'content-type': 'application/json' `を指定したリクエストを GAS に送った場合) GAS との通信は CORS policy によりブロックされます。
|
113
114
|
|
114
115
|
> ・postparamに「mode: 'no-cors'」を追加したところ、「成功」が表示されましたが、スプレッドシートに書き込まれませんでした。
|
115
116
|
|
116
|
-
「mode: 'no-cors'」に設定すると、レスポンスは [opaque
|
117
|
-
となり、GAS から JSON を返しても無視されて、空っぽのデータが返ってきます。
|
117
|
+
「mode: 'no-cors'」に設定すると、たしかに CORS エラーは発生しませんが、レスポンスは [opaque](https://developer.mozilla.org/ja/docs/Web/API/Response/type#:~:text=opaque%3A%20%E3%82%AA%E3%83%AA%E3%82%B8%E3%83%B3%E9%96%93%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9%E3%81%B8%E3%81%AE%20%22no%2Dcors%20%22%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%81%AB%E5%AF%BE%E3%81%99%E3%82%8B%E3%83%AC%E3%82%B9%E3%83%9D%E3%83%B3%E3%82%B9%E3%80%82%20%E5%8E%B3%E3%81%97%E3%81%8F%E5%88%B6%E9%99%90%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82) となり、GAS から JSON を返しても無視されて、空っぽのデータが返ってきます。
|
118
118
|
|
119
119
|
つまり GAS 内部でエラーがあろうとなかろうと、no-cors にしていると空っぽのレスポンスがポツンと返ってくるわけで(エラー扱いにならないので fetch の .catch にもつかまりません)、上のコードで「成功」と表示されたからと言ってGAS側が正常であるとは限りません。
|
120
120
|
|
6
test
CHANGED
@@ -70,9 +70,7 @@
|
|
70
70
|
const res = doPostPloxy(e);
|
71
71
|
return res;
|
72
72
|
} catch (err) {
|
73
|
-
SpreadsheetApp.openById(sheet_id).getSheetByName("log").appendRow([err.stack]);
|
74
|
-
return ContentService.createTextOutput(JSON.stringify({ result:err.stack}));
|
73
|
+
return ContentService.createTextOutput(JSON.stringify({ result: err.stack}));
|
75
|
-
|
76
74
|
}
|
77
75
|
}
|
78
76
|
function doPostPloxy(e) {
|
5
test
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
|
2
|
+
「・投稿内容すべてをjavascriptで一括でPOSTして、GASでスプレッドシートに書き込みたい」について
|
2
3
|
先に動作する回答例を示して、後半で解説します。(コメントやコードの大部分は、元質問のものを残しておりますのでご了承ください)
|
4
|
+
|
5
|
+
(2番目の「・投稿内容すべてをスプレッドシートから一括でGETして、リストに表示したい」については具体的なコードが質問に一切示されておらず要件が全く不明であるため、割愛します)
|
6
|
+
|
3
7
|
**<例>**
|
4
8
|
**クライアント側HTML** sample.html
|
5
9
|
```html
|
4
test
CHANGED
@@ -172,10 +172,10 @@
|
|
172
172
|
}
|
173
173
|
```
|
174
174
|
|
175
|
-
##### ④
|
175
|
+
##### ④ 未定義の変数
|
176
176
|
ss という変数が内部で使われていますがどこにも定義されていません。おそらくスプレッドシートのことだろうと推測したので、とりあえずスプレッドシートオブジェクトを格納したグローバル変数として定義しています。
|
177
177
|
|
178
|
-
##### ⑤
|
178
|
+
##### ⑤ グローバル変数の(意図しない?)上書き
|
179
179
|
グローバル変数で定義している sheet という変数が doPost内で上書きされており、このために期待する動作になっていません。
|
180
180
|
sheet はローカル変数とし、postJsonToSpreadSheet に引数として渡すようにすればよいでしょう。(修正後コード中の変数「targetSheet」参照)
|
181
181
|
|
3
test
CHANGED
@@ -173,11 +173,11 @@
|
|
173
173
|
```
|
174
174
|
|
175
175
|
##### ④ あるべき変数がない。
|
176
|
-
ss という変数が内部で使われていますがどこにも定義されていません。おそらくスプレッドシート
|
176
|
+
ss という変数が内部で使われていますがどこにも定義されていません。おそらくスプレッドシートのことだろうと推測したので、とりあえずスプレッドシートオブジェクトを格納したグローバル変数として定義しています。
|
177
177
|
|
178
178
|
##### ⑤ sheet 変数の上書き
|
179
|
-
グローバル変数で定義している sheet という変数が doPost内で上書きされて
|
179
|
+
グローバル変数で定義している sheet という変数が doPost内で上書きされており、このために期待する動作になっていません。
|
180
|
-
sheet はローカル変数とし、postJsonToSpreadSheet に引数として渡すようにすればよいでしょう。
|
180
|
+
sheet はローカル変数とし、postJsonToSpreadSheet に引数として渡すようにすればよいでしょう。(修正後コード中の変数「targetSheet」参照)
|
181
181
|
|
182
182
|
|
183
183
|
|
2
test
CHANGED
@@ -152,9 +152,9 @@
|
|
152
152
|
+ 正常終了の場合 → Access-Control-Allow-Origin * 付きでレスポンスが返ってくる
|
153
153
|
+ エラーが発生した場合 → Access-Control-Allow-Origin なしで返ってくる → CORS policy によりブロックされる
|
154
154
|
|
155
|
-
エラー
|
155
|
+
修正前のコードだと、GAS側でエラーが発生して終了しても、クライアント側では CORS policy によりブロックされたということしかわかりません。(GAS 内部のエラー内容をクライアント側スクリプトの catch ブロックで取り出すことはできません)
|
156
156
|
|
157
|
-
した
|
157
|
+
GAS 内部で発生したエラー内容を捕捉したいのであれば、GAS 側で doPost 内の処理を丸ごと try ~ catch ブロックで囲み、例外処理の中でエラー内容を(正常に)返すようなギミックを使います。(同時にエラー内容をログシートに出力するようにしてもよいでしょう)
|
158
158
|
```js
|
159
159
|
// Postリクエスト処理中のエラーをトラップするため try ~ catch で囲む。
|
160
160
|
function doPost(e) {
|
1
test
CHANGED
@@ -154,7 +154,7 @@
|
|
154
154
|
|
155
155
|
エラーの場合、CORS policy によりブロックされるため、レスポンス内容を クライアント側スクリプトの catch ブロックで取り出すことはできません。
|
156
156
|
|
157
|
-
したがってエラー内容を捕捉したいのであれば、GAS 側で try ~ catch ブロックで囲
|
157
|
+
したがってエラー内容を捕捉したいのであれば、GAS 側で doPost 内の処理を丸ごと try ~ catch ブロックで囲み、例外処理の中でエラー内容を(正常に)返すようなギミックを使います。(同時にエラー内容をログシートに出力するようにしてもよいでしょう)
|
158
158
|
```js
|
159
159
|
// Postリクエスト処理中のエラーをトラップするため try ~ catch で囲む。
|
160
160
|
function doPost(e) {
|