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

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

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

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

Express

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

Q&A

解決済

1回答

849閲覧

Expressでchild_process出力のハンドリング方法

S.Nakagawa255

総合スコア20

Node.js

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

Express

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

0グッド

0クリップ

投稿2022/05/01 23:15

編集2022/05/01 23:16

前提

ExpressでユーザがWebブラウザ操作をしたらサーバ内プログラム(Windows バッチファイル)の出力結果を画面上に表示するシステムを試作しています。
今回はやり方を学ぶためdirコマンドにしていますが、将来的には独自プログラムで処理を行いその結果をWebブラウザで表示することを想定しています。

child_processモジュールにてサーバ上の実行可能ファイルを呼び出せたのですが出力がコンソールにもWebブラウザ側にも表示されません。

実現したいこと

  1. http://localhost:3000/dir を実行
  2. 画面上にdirコマンドの出力結果が表示される

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

VSCodeのターミナル上には以下のメッセージしか表示されません。
Web画面

PowerShell

1PS C:\dirservice> SET DEBUG=dirservice.* 2& npm start 3 4Id Name PSJobTypeName State HasMoreData Location Command 5-- ---- ------------- ----- ----------- -------- ------- 61 Job1 BackgroundJob Running True localhost Microsoft.Po… 7 8> dirservice@0.0.0 start C:\dirservice 9> node ./bin/www 10 11GET / 304 5280.695 ms - - 12GET /stylesheets/style.css 304 2.375 ms - - 13GET /favicon.ico 404 18.653 ms - 1582 14GET /dir 200 1.494 ms - 8

Webブラウザ
イメージ説明

該当のソースコード

Expressジェネレータで作成して、dir.bat、dir.jsを足しています。

PowerShell

1PS> npm install express-generator -g 2PS> express --view=pug dirservice 3PS> cd dirservice 4PS> npm install 5PS> SET DEBUG=dirservice:* & npm start

フォルダ構成は以下です。

C:\WORK | .gitignore | \---dirservice | app.js | dir.txt | package-lock.json | package.json | +---bin | dir.bat | www | +---node_modules | +---public | +---images | +---javascripts | \---stylesheets | style.css | +---routes | dir.js | index.js | users.js | \---views error.pug index.pug layout.pug

dir.bat

bat

1@echo off 2dir

dir.js

JavaScript

1var express = require('express'); 2var router = express.Router(); 3var exec = require('child_process').exec; 4 5/* GET home page. */ 6router.get('/', function(req, res, next) { 7 res.send('GET dir!'); 8 exec('cmd.exe ../bin/dir.bat', function(error, stdout, stderr) { 9 if (error != null) { 10 console.log(error); 11 } 12 console.log('stdout: ${stdout}'); 13 console.log('stderr: ${stderr}'); 14 res.send('stdout: ${stdout}'); 15 res.send('stderr: ${stderr}'); 16 17 }); 18}); 19 20module.exports = router; 21

app.js、localhost:3000/dir にアクセスしたときdir.jsへルーティングする設定を追加しています。

JavaScript

1var createError = require('http-errors'); 2var express = require('express'); 3var path = require('path'); 4var cookieParser = require('cookie-parser'); 5var logger = require('morgan'); 6 7var indexRouter = require('./routes/index'); 8var usersRouter = require('./routes/users'); 9var dirRouter = require('./routes/dir'); 10 11var app = express(); 12 13// view engine setup 14app.set('views', path.join(__dirname, 'views')); 15app.set('view engine', 'pug'); 16 17app.use(logger('dev')); 18app.use(express.json()); 19app.use(express.urlencoded({ extended: false })); 20app.use(cookieParser()); 21app.use(express.static(path.join(__dirname, 'public'))); 22 23app.use('/', indexRouter); 24app.use('/users', usersRouter); 25app.use('/dir', dirRouter); 26 27// catch 404 and forward to error handler 28app.use(function(req, res, next) { 29 next(createError(404)); 30}); 31 32// error handler 33app.use(function(err, req, res, next) { 34 // set locals, only providing error in development 35 res.locals.message = err.message; 36 res.locals.error = req.app.get('env') === 'development' ? err : {}; 37 38 // render the error page 39 res.status(err.status || 500); 40 res.render('error'); 41}); 42 43module.exports = app;

以下、Expressジェネレータで作成されたまま使用しています。
bin/www

JavaScript

1#!/usr/bin/env node 2 3/** 4 * Module dependencies. 5 */ 6 7var app = require('../app'); 8var debug = require('debug')('dirservice:server'); 9var http = require('http'); 10 11/** 12 * Get port from environment and store in Express. 13 */ 14 15var port = normalizePort(process.env.PORT || '3000'); 16app.set('port', port); 17 18/** 19 * Create HTTP server. 20 */ 21 22var server = http.createServer(app); 23 24/** 25 * Listen on provided port, on all network interfaces. 26 */ 27 28server.listen(port); 29server.on('error', onError); 30server.on('listening', onListening); 31 32/** 33 * Normalize a port into a number, string, or false. 34 */ 35 36function normalizePort(val) { 37 var port = parseInt(val, 10); 38 39 if (isNaN(port)) { 40 // named pipe 41 return val; 42 } 43 44 if (port >= 0) { 45 // port number 46 return port; 47 } 48 49 return false; 50} 51 52/** 53 * Event listener for HTTP server "error" event. 54 */ 55 56function onError(error) { 57 if (error.syscall !== 'listen') { 58 throw error; 59 } 60 61 var bind = typeof port === 'string' 62 ? 'Pipe ' + port 63 : 'Port ' + port; 64 65 // handle specific listen errors with friendly messages 66 switch (error.code) { 67 case 'EACCES': 68 console.error(bind + ' requires elevated privileges'); 69 process.exit(1); 70 break; 71 case 'EADDRINUSE': 72 console.error(bind + ' is already in use'); 73 process.exit(1); 74 break; 75 default: 76 throw error; 77 } 78} 79 80/** 81 * Event listener for HTTP server "listening" event. 82 */ 83 84function onListening() { 85 var addr = server.address(); 86 var bind = typeof addr === 'string' 87 ? 'pipe ' + addr 88 : 'port ' + addr.port; 89 debug('Listening on ' + bind); 90} 91

error.pug

pug

1extends layout 2 3block content 4 h1= message 5 h2= error.status 6 pre #{error.stack}

index.pug

pug

1extends layout 2 3block content 4 h1= title 5 p Welcome to #{title}

layout.pug

pug

1doctype html 2html 3 head 4 title= title 5 link(rel='stylesheet', href='/stylesheets/style.css') 6 body 7 block content

index.js

JavaScript

1var express = require('express'); 2var router = express.Router(); 3 4/* GET home page. */ 5router.get('/', function(req, res, next) { 6 res.render('index', { title: 'Express' }); 7}); 8 9module.exports = router;

users.js

JavaScript

1var express = require('express'); 2var router = express.Router(); 3 4/* GET users listing. */ 5router.get('/', function(req, res, next) { 6 res.send('respond with a resource'); 7}); 8 9module.exports = router;

補足情報(FW/ツールのバージョンなど)

PowerShell

1PS> node --version 2v14.18.1

package.json

json

1{ 2 "name": "dirservice", 3 "version": "0.0.0", 4 "private": true, 5 "scripts": { 6 "start": "node ./bin/www" 7 }, 8 "dependencies": { 9 "cookie-parser": "~1.4.4", 10 "debug": "~2.6.9", 11 "encoding-japanese": "^2.0.0", 12 "express": "~4.16.1", 13 "http-errors": "~1.6.3", 14 "morgan": "~1.9.1", 15 "pug": "2.0.0-beta11" 16 } 17}

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

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

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

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

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

guest

回答1

0

ベストアンサー

こんな感じでしょうか。ポイントは、

  • res.send は 1 回しか呼んではいけません。2 回目以降はエラーになります。
    ('GET dir!' を表示したければ console.log しましょう。)
  • cmd.exe に bat ファイルを渡す場合は /c オプションが必要なようです。
    (これがないとコマンド入力待ちになって cmd.exe は終了せず、残りの部分は実行されません。)
  • dir.bat の相対パスの起点は dir.js がある場所ではなく、カレントディレクトリ (npm start した場所) になります。
    さらに、パスの区切りは / ではなく \ (文字列中では \\) とする必要があるようです。
    (ついでに言うと、cmd.exe /c なしで 'bin\\dir.bat' だけでも良いみたい。)
  • ${stdout} のように文字列中に式を展開したい場合は、シングルクォート ' ではなくバッククォート ` で囲みます。
    また、res.send は 1 回しか使えないので、stdout と stderr はまとめて出力しましょう。
    (あと、何も指定しないと HTML として出力されて表示が崩れるので、Content-Type: text/plain にすると良いかも。)

js

1// dir.js 2router.get('/', function(req, res, next) { 3 exec('cmd.exe /c bin\\dir.bat', function(error, stdout, stderr) { 4 if (error != null) { 5 console.log(error); 6 } 7 console.log(`stdout: ${stdout}`); 8 console.log(`stderr: ${stderr}`); 9 res.set('Content-Type', 'text/plain'); 10 res.send(`stdout: ${stdout}\nstderr: ${stderr}`); 11 }); 12});

投稿2022/05/02 04:00

hoshi-takanori

総合スコア7895

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

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

S.Nakagawa255

2022/05/02 04:17

ポイントを分かりやすくありがとうございます! おかげさまで次のステップに進めそうです!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問