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

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

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

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

REST

REST(Representational State Transfer)はwebアプリケーションの構築スタイルの一種です。HTTP GET/POSTによってリクエストを送信し、レスポンスはXMLで返されます。SOAPのようなRPCの構築と比べるとサーバからクライアントを分離することが出来る為、人気です。

JavaScript

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

Express

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

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

Q&A

解決済

2回答

1978閲覧

Node.js+expressで構築したAPIサーバーで同時リクエストを並列処理したい。

odebumaru

総合スコア1

Node.js

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

REST

REST(Representational State Transfer)はwebアプリケーションの構築スタイルの一種です。HTTP GET/POSTによってリクエストを送信し、レスポンスはXMLで返されます。SOAPのようなRPCの構築と比べるとサーバからクライアントを分離することが出来る為、人気です。

JavaScript

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

Express

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

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

0グッド

0クリップ

投稿2023/04/15 15:58

編集2023/04/15 17:54

実現したいこと

Node.js+expressで構築したAPIサーバーで同時リクエストを並列処理したい。

(例)
リクエストを受け付けてからレスポンスを返すまでに3秒かかる処理があるとする。
3台のクライアントが同時に該当のURIにリクエストを送信した際に、下記のような順番で処理をしてほしい。

  • ① クライアント1のリクエストを受け付け・処理を開始
  • ② クライアント2のリクエストを受け付け・処理を開始
  • ③ クライアント3のリクエストを受け付け・処理を開始
  • (3秒の処理)
  • ④ ①の処理が完了・レスポンスを返す
  • ⑤ ②の処理が完了・レスポンスを返す
  • ⑥ ③の処理が完了・レスポンスを返す

前提

Node.js+expressでAPIサーバーを構築しています。

同時リクエストに対して、並列で処理を行いレスポンスを返却したいのですが、上手く実装できず、ご質問させていただきます。

該当のソースコード

JavaScript

1const express = require('express'); 2const app = express(); 3const port = process.env.PORT || 3000; 4 5app.listen(port, () => console.log(`Listening on port ${port}...`)); 6 7app.get('/', (req, res) => { 8 console.log("accept request"); 9 10 let resMsg = ''; 11 12 setTimeout(() => { 13 // 3秒後にレスポンスメッセージが決まり、レスポンスが送信可能 14 resMsg = 'THIS IS RESPONSE MESSAGE'; 15 console.log("send response"); 16 res.send(resMsg); 17 }, 3000); 18})

試したこと

上記コードで起動したサーバーの該当URIとportに同時に3回リクエストを送った際、
3つの処理が同期的に処理され、コンソールログは下記のようになってしまいます。(acceptとsendのログの間に3秒間の間があり、全体で9秒かかっている)

Listening on port 3000... accept request send response accept request send response accept request send response

実現させたい動きは、1番目のレスポンスを送信する前に2番目のリクエストを受け付けるようにすることです。
その場合コンソールログは、下記のようになることを想定しております。(ほぼ同時にacceptログが3回出て3秒後にsendログが3回出力され、全体の処理も3秒程度で完了する)

Listening on port 3000... accept request accept request accept request send response send response send response

Node.jsではノンブロッキングI/O処理によって、大量リクエストの並列処理が可能という情報があり、上記コードで実現できると思っていたのですが上手くいかず、、
そもそもレスポンスを返す前に、同じURIのリクエストを受け付けることが可能なのでしょうか。。
実現方法をご教示いただけますと幸いです。

補足情報(バージョン)

ModuleVer.
Node.jsv14.18.1
express4.18.2

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

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

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

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

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

dameo

2023/04/15 22:21

クライアント側の実装が悪いのでは?環境を明記して、クライアント側での確認方法を記載しましょう。
dameo

2023/04/15 22:27

手元の環境だとバージョン違うけど、問題ないですよ。 $ node --version v16.18.0 $ cat server.js const express = require('express'); const app = express(); const port = process.env.PORT || 3000; app.listen(port, () => console.log(`Listening on port ${port}...`)); app.get('/', (req, res) => { console.log("accept request"); let resMsg = ''; setTimeout(() => { // 3秒後にレスポンスメッセージが決まり、レスポンスが送信可能 resMsg = 'THIS IS RESPONSE MESSAGE'; console.log("send response"); res.send(resMsg); }, 3000); }) $ node server.js& [1] 97190 $ Listening on port 3000... $ for _ in `seq 3`;do sh -c "date;wget --quiet -O - 'http://localhost:3000';date"&done [2] 97202 [3] 97203 [4] 97204 $ 2023年 4月 16日 日曜日 07:26:14 JST 2023年 4月 16日 日曜日 07:26:14 JST 2023年 4月 16日 日曜日 07:26:14 JST accept request accept request accept request send response THIS IS RESPONSE MESSAGE2023年 4月 16日 日曜日 07:26:17 JST send response THIS IS RESPONSE MESSAGEsend response 2023年 4月 16日 日曜日 07:26:17 JST THIS IS RESPONSE MESSAGE2023年 4月 16日 日曜日 07:26:17 JST [2] 終了 sh -c "date;wget --quiet -O - 'http://localhost:3000';date" [3]- 終了 sh -c "date;wget --quiet -O - 'http://localhost:3000';date" [4]+ 終了 sh -c "date;wget --quiet -O - 'http://localhost:3000';date" $
dameo

2023/04/15 22:36

追記 $ npm list express tmp@1.0.0 /home/user/tmp └── express@4.18.2 $
odebumaru

2023/04/16 06:33 編集

実際の動作確認まで、ありがとうございます。 ご指摘の通り、クライアント側(ブラウザの制御)の問題のようでした。。 試しにコマンドラインで、curl --pararell で確認したところ、問題なく動作することを確認できました。 クライアント側は、Vue.jsでaxiosを使用しており、ボタンを押したらaxios.getが動くような実装です。 ボタンを連打したり、axious.getをfor分で回してもどうも上手くいかないようでしたが、どうやらブラウザ側の制御が原因のようでした(Edge,Chromeともに実行不可でした)。 Chromeの開発者ツールのNetworkタブで確認したところ、 ブラウザ側で送信制御がされており、1つのリクエストの返信が返ってくるまで、他のリクエストは"Stalled"の状態でAPIサーバーへ送信されていないことがわかりました。 http://localhost:3000とhttp://localhost:3000/getのように別パスのURIであれば並列のリクエストが実行可能であったので、同じパスだと同期的にしかリクエストを送信できない?ような作りなのかなと予想しております。 これはこれで疑問なのですが、QAで挙げさせていただいたNode.jsは並列処理ができていることが分かったため、解決済みとさせていただきます。 大変助かりました。ありがとうございました。
guest

回答2

0

自己解決

Node.jsのソースコードは問題なく同時リクエストに対する並列処理ができていることがわかりました。

問題は私が動作確認時に試していたブラウザでの制御(Chrome,Edge)が原因でして、
同一セッションで同一URIへ同時リクエストを送信した際に、1つのリクエストはAPIサーバーに送信されますが、それ以外は"Stalled"のステータスでリクエストが送信されていないことが分かりました(1つ目のレスポンスが返ってきた後で順次"Stalled"のリクエストが同期的に送信されていきます)

■下記Chrome 開発者ツールで確認
1つ目のリクエスト(即時リクエストが送信)
イメージ説明
2つ目のリクエスト(1つ目のリクエストが返ってくるまで"Stalled"状態)
イメージ説明
3つ目のリクエスト(2つ目のリクエストが返ってくるまで"Stalled"状態)
イメージ説明

本件はQAタイトルのNode.jsの処理とは無関係であったため、解決とさせていただきます。
(ブラウザ側で上記制御が働いていることについては、調べても良く分からず疑問ですが、、)

皆様のご協力大変ありがとうございました。

投稿2023/04/16 06:48

odebumaru

総合スコア1

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

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

dameo

2023/04/16 07:45 編集

HTMLを静的に返せるようにしただけ。 $ cat server.js const express = require('express'); const app = express(); const port = process.env.PORT || 3000; app.listen(port, () => console.log(`Listening on port ${port}...`)); app.use(express.static('.')); app.get('/', (req, res) => { console.log("accept request"); let resMsg = ''; setTimeout(() => { // 3秒後にレスポンスメッセージが決まり、レスポンスが送信可能 resMsg = 'THIS IS RESPONSE MESSAGE'; console.log("send response"); res.send(resMsg); }, 3000); }) 返すHTMLの内容 $ cat hoge.html <script type="importmap"> { "imports": { "vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js", "axios": "https://cdn.jsdelivr.net/npm/@bundled-es-modules/axios@0.27.2/+esm" } } </script> <div id="app"> <button @click="test"> test() </button> </div> <script type="module"> import { createApp } from 'vue'; import { axios } from 'axios'; createApp({ methods: { async test() { const url = 'http://localhost:3000/'; console.log(new Date() + ': ' + 'start test'); (await Promise.all([axios.get(url), axios.get(url), axios.get(url)])) .forEach((res)=> { console.log(new Date() + ': ' + res.data); }); } }, }).mount('#app') </script> $ node server.jsしてからブラウザでhttp://localhost:3000/開くだけで、コンソールで確認できる。
guest

0

Node.jsではノンブロッキングI/O処理によって、大量リクエストの並列処理が可能という情報があり

Node.jsはデフォルトではシングルスレッドで動作するため、
提示された同期的なコードではマルチスレッドのように処理させるできません。
下記のように非同期処理を用いることで、実現可能です。

js

1app.get('/', async (req, res) => { 2 console.log("accept request"); 3 4 // 非同期処理でレスポンスを返すまでに、3秒かかる想定で記載 5 await new Promise(resolve => setTimeout(resolve, 3000)); 6 7 console.log("send response"); 8 res.send('THIS IS RESPONSE MESSAGE.'); 9});

投稿2023/04/15 16:33

pippi19

総合スコア679

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

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

odebumaru

2023/04/15 17:56 編集

ご回答いただき、ありがとうございます。 ご提示くださったコードで試してみましたが、想定通り動きませんでした、、 また1点、言葉が足りていなく申し訳ございませんが、リクエスト受信~レスポンス送信までは、必ず3秒間かかるような状況を想定しております。 (3秒後にレスポンスメッセージが決まるようなイメージです。分かりにくかったため、質問内容のソースコードを部分的に修正させていただきました。) 色々試してみましたが、res.send() が実行されるまでは、2回目のリクエスト処理が始まらないように見えます。。シングルスレッドである以上難しいのでしょうか。。。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問