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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Express

ExpressはNode.jsのWebアプリケーションフレームワークです。 マルチページを構築するための機能セットおよびハイブリッドのWebアプリケーションを提供します。

Q&A

解決済

1回答

1598閲覧

Express res.json()で処理を終了する方法

watter

総合スコア15

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Express

ExpressはNode.jsのWebアプリケーションフレームワークです。 マルチページを構築するための機能セットおよびハイブリッドのWebアプリケーションを提供します。

1グッド

1クリップ

投稿2021/08/21 06:09

編集2021/08/21 12:21

Express res.json()で処理を終了する方法

Expressを用いて以下のようなコードを実装しました。

javascript

1router.post('/', (req, res) => { 2 --省略-- 3 if (flag) { 4 res.json('data1': data1) 5 } 6 7 res.json('data2': data2) 8})

この処理が呼び出されたとき、flagがfalseであれば問題はないのですが、flagがtrueのときにres.json('data1': data1)が呼び出された後に、res.json('data2': data2)も呼び出され、

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

という2度レスポンスが送られた旨のエラーが発生します。

javascript

1router.post('/', (req, res) => { 2 --省略-- 3 if (flag) { 4 res.json('data1': data1) 5 } else { 6 res.json('data2': data2) 7 } 8})

とすれば当然エラーは発生しなくなります。このような仕様になっているのはres.json()の後も処理が行われることが前提となっているためですが、res.json()の後に処理をする必要がなく、それらの処理を無視したい場合

javascript

1router.post('/', (req, res) => { ・・・➀ 2 --省略-- 3 if (flag) { 4 res.json('data1': data1) 5 ➀を終了させる処理 6 } 7 8 res.json('data2': data2) 9 ➀を終了させる処理 10})

のように「➀を終了させる処理」は存在するのでしょうか。

追記が多くなってしまったので少しまとめます。
・returnを使う方法 → ➀内でさらに関数を(メソッドの引数などで)呼び出し、その関数内でres.json()を実行するときに➀を抜けられない。入れ子にしないなら使える。

この他に何かよい方法をご存知でしたらぜひお教えください

###追記
実際には

javascript

1router.post('/', (req, res) => { 2 --省略-- 3 if (flag) { 4 return res.json('data1': data1) 5 } else { 6 return res.json('data2': data2) 7 } 8})

のように実装していたのですが、

javascript

1router.post('/', (req, res) => { ・・・Ⅰ 2 --省略-- 3 AAAA() 4 .then((flag) => { ・・・Ⅱ 5 if(flag) { 6 return res.json('data1': data1) ・・・Ⅲ 7 } else { 8 return res.json('data2': data2) ・・・Ⅳ 9 } 10 }) 11 .then((DATA) => { //res.json()の戻り値 12 --省略-- 13 }) 14 15 return res.json('data3': data3) ・・・Ⅴ 16})

のようなコードを考えた時、
ⅢもしくはⅣが実行されるのはⅡの関数内であり、このreturnではres.jsonの戻り値がDATAとして次の関数に渡されるだけでⅠを抜けられないことからreturn以外の方法があればと思い質問しました。
説明が不足しており、大変申し訳ありませんでした。

###追記2
確かに上記のコードではⅤが先に実行されますね。
コードを修正します。

javascript

1router.post('/', (req, res) => { ・・・Ⅰ 2 --省略-- 3 AAAA() 4 .then((flag) => { ・・・Ⅱ 5 if(flag) { 6 return res.json('data1': data1) ・・・Ⅲ 7 } else { 8 return res.json('data2': data2) ・・・Ⅳ 9 } 10 --省略-- 11 }) 12 .then((DATA) => { //res.json()の戻り値 13 --省略-- 14 return res.json('data3': data3) ・・・Ⅴ 15 }) 16})

このコードではⅢもしくはⅣが実行された後にⅤが実行されエラーになると思います。

#追記3

javascript

1router.post('/', (req, res) => { ・・・Ⅰ 2 --省略-- 3 AAAA() 4 .then((flag) => { ・・・Ⅱ 5 if(flag) { 6 return res.json('data1': data1) ・・・Ⅲ 7 } else { 8 return res.json('data2': data2) ・・・Ⅳ 9 } 10 --省略-- 11 }) 12 .then((DATA) => { //res.json()の戻り値 13 --省略-- 14 return res.json('data3': data3) ・・・Ⅴ 15 }) 16})

この処理をreturnが使えない例として挙げたのはよくなかったかもしれません…
res.json()の実行後にⅠを抜ける共通処理的なものはあるのでしょうか。

Waki285👍を押しています

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

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

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

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

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

hoshi-takanori

2021/08/21 11:48

それだと V がまず実行されて、非同期で III または IV が実行されるのでは…。 最近 express 書いてないのでよく分かりませんが、返事を確実に 1 回だけ返すには async/await を使うのがいいんじゃないかという気がします。 https://qiita.com/yukin01/items/1a36606439123525dc6d
guest

回答1

0

ベストアンサー

プログラミングの問題です。

res.jsonは一度しか実行してはいけません。
でも1度は確実に実行したいわけじゃないですか。
だったら関数の末尾に書けばよくね?って話です。

js

1router.post('/', (req, res) => { 2 let result = null; 3 4 // --省略-- 5 if (flag) { 6 result = {data1: data1}; 7 } 8 9 // 初期の質問をベースにするならこういう逃げ方が良いかな 10 if (result == null) { 11 result = {data2: data2}; 12 } 13 14 // 共通の終了処理があるならres.jsonの前後で指定すれば良いね 15 res.json(result); 16})

関数でまるっと包んでも良いと思います。

js

1// 複雑な事をやっている検索システムという体で適当な関数名にした 2const awesomeSearch = (connection) => { 3 // --省略-- 4 5 if (flag) { 6 return {data1: data1}; 7 } 8 9 return {data2: data2}; 10} 11 12router.post('/', (req, res) => { 13 // 事前準備としてconnectionみたいなのを準備 14 const connection = {}; 15 16 res.json(awesomeSearch(connection)); 17 // 終了処理を挟んでconnectionを処理 18})

いやいや、発展した質問部分のようにPromiseを使って非同期でやってるから無理だよ!

async/awaitを使ってください。
「追記3」のコードをベースに改修するとこうなります。

js

1// 関数の前にasyncキーワードを付与することで 2// awaitが使えるasync関数になる 3router.post('/', async (req, res) => { 4 let result = {}; 5 6 // --省略-- 7 8 // Promiseインスタンスを返すAAAA関数の実行→resolveを取り出す処理はこう書ける 9 const flag = await AAAA(); 10 if (flag) { 11 result.data1 = data1; 12 } 13 14 // 初期のresultが{}なのでキーの数で空か否かを決定する逃げ方に変更してみた 15 if (Object.keys(result).length == 0) { 16 result.data2 = data2; 17 } 18 19 // 上記AAAA関数のthenを同期的に叩けるようになるので 20 // 複雑な処理を経由した後のDATAもこのレベルに記述出来るはず 21 if (DATA) { 22 result.data3 = data3; 23 } 24 25 res.json(result); 26})

投稿2021/08/22 13:54

編集2021/08/22 13:54
miyabi-sun

総合スコア21203

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

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

watter

2021/08/23 03:28

なるほど、resultを用意してからさいごにまとめてres.jsonする...思いつきませんでした。ご回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問