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

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

新規登録して質問してみよう
ただいま回答率
85.35%
HTTPヘッダー

Hypertext Transfer Protocol(HTTP)の中のHTTPヘッダフィールドはHTTPの要求やレスポンスの機能しているパラメーターが含まれます。その要求もしくはレスポンスライン(メッセージの最初の一行)でメッセージヘッダを作ります。

Node.js

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

REST

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

Express

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

API

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

Q&A

解決済

2回答

2060閲覧

expressで、res.json()すると、ヘッダーをセットできない

masaking

総合スコア30

HTTPヘッダー

Hypertext Transfer Protocol(HTTP)の中のHTTPヘッダフィールドはHTTPの要求やレスポンスの機能しているパラメーターが含まれます。その要求もしくはレスポンスライン(メッセージの最初の一行)でメッセージヘッダを作ります。

Node.js

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

REST

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

Express

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

API

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

0グッド

0クリップ

投稿2020/03/30 13:49

編集2020/03/30 14:59

expressにて、reactに情報を渡すためのapi作りにチャレンジしています。

postmanで確認すると、json自体は帰っているのですが、

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
とエラーが出ています。

なぜこのようなエラーが出ていて、どのようにすればエラーが出ずにアプリがアプリがクラッシュしないのでしょうか。


big5db.js

js

1var express = require('express'); 2var router = express.Router(); 3 4const client = require('mongodb').MongoClient; 5const url = 'mongodb://localhost:27017'; 6 7client.connect(url, { useUnifiedTopology: true }, function (err, client) { 8 9 var db = client.db("test_db"); 10 var collection = db.collection("Big5"); 11 12 var query = {}; 13 var projection = { 14 "personality.name": "$personality.name", 15 "personality.percentile": "$personality.percentile", 16 "personality.trait_id": "$personality.trait_id", 17 "_id": 0 18 }; 19 20 var cursor = collection.find(query).project(projection); 21 22 23router.get('/',function(req,res,next){ 24 cursor.forEach( 25 function(doc) { 26 var data = doc.personality.map(({name, trait_id, percentile}) => ({name, trait_id, percentile})) 27 //res.render('big5db.ejs',{big5s: data}); 28 res.status(200).json(data); 29 }, 30 function(err) { 31 client.close(); 32 } 33 ); 34}); 35 36 37router.get('/big5_openness',(req,res,next)=>{ 38 cursor.forEach( 39 function(doc) { 40 var data = doc.personality[0].children.map(({name,percentile}) => ({name,percentile})) 41 return res.json(data); 42 } 43 ); 44 }); 45 46router.get('/big5_conscientiousness',(req,res,next)=>{ 47 cursor.forEach( 48 function(doc) { 49 var data = doc.personality[1].children.map(({name,percentile}) => ({name,percentile})) 50 return res.json(data); 51 } 52 ); 53 }); 54 55router.get('/big5_extraversion',(req,res,next)=>{ 56 cursor.forEach( 57 function(doc) { 58 var data = doc.personality[2].children.map(({name,percentile}) => ({name,percentile})) 59 return res.json(data); 60 } 61 ); 62 }); 63 64router.get('/big5_agreeableness',(req,res,next)=>{ 65 cursor.forEach( 66 function(doc) { 67 var data = doc.personality[3].children.map(({name,percentile}) => ({name,percentile})) 68 return res.json(data); 69 } 70 ); 71 }); 72 73router.get('/big5_neuroticism',(req,res,next)=>{ 74 cursor.forEach( 75 function(doc) { 76 var data = doc.personality[4].children.map(({name,percentile}) => ({name,percentile})) 77 return res.json(data); 78 } 79 ); 80 }); 81 82}); 83 84module.exports = router; 85

app.js

js

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 big5db = require('./routes/big5db'); 10var twitter = require('./routes/twitter'); 11 12var app = express(); 13 14// view engine setup 15app.set('views', path.join(__dirname, 'views')); 16app.set('view engine', 'ejs'); 17 18app.use(logger('dev')); 19app.use(express.json()); 20app.use(express.urlencoded({ extended: false })); 21app.use(cookieParser()); 22app.use(express.static(path.join(__dirname, 'public'))); 23 24app.use('/', indexRouter); 25app.use('/users', usersRouter); 26app.use('/twitter', twitter); 27app.use('/big5db', big5db); 28 29 30// catch 404 and forward to error handler 31app.use(function(req, res, next) { 32 next(createError(404)); 33}); 34 35// error handler 36app.use(function(err, req, res, next) { 37 // set locals, only providing error in development 38 res.locals.message = err.message; 39 res.locals.error = req.app.get('env') === 'development' ? err : {}; 40 41 // render the error page 42 res.status(err.status || 500); 43 res.render('error'); 44}); 45 46module.exports = app;

例えば、http://localhost:5001/big5db/にゲットリクエストを送ると、以上のようなエラーが出ます。
参考などを見たモノの、一つのパスにつき、resは一回だけにしているので、なぜこれでheaderを二回もセットしているよ、とエラーが出るのかわかりません。

基本的なこととは思いますが、ご教授いただけると幸いです。
また、express-generatorで雛形を構築しております。
それを使わないバージョンでも試したのですが、やはり同じ状況でした。

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

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

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

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

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

guest

回答2

0

一つのパスにつき、resは一回だけにしている

残念ながら、cursor.forEach ということは複数の結果に対してそれぞれ callback が呼ばれるので、一回ではなく複数回になると思います。(結果が空なら 0 回の可能性もあるのでは。)

mongodb は詳しくありませんが、ドキュメントには toArray というメソッドがありますので、これを使ったら良いのではないでしょうか。
参考: toArray - Class: Cursor

また、cursor は一回しか作られないのに、それをリクエストのたびに使ってるので、二回目以降の API アクセスは動かないのでは…。

投稿2020/03/30 21:10

編集2020/03/30 21:11
hoshi-takanori

総合スコア7901

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

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

masaking

2020/04/01 23:53

ありがとうございます。 Arrayで出力した後、繰り返しで抜き出す処理をすることで対応できました。 ありがとうございます。
guest

0

ベストアンサー

なぜこのようなエラーが出ていて、

db の走査(forEach()のループ)を完了する前に、HTTP応答しているためです。

どのようにすればエラーが出ずにアプリがアプリがクラッシュしないのでしょうか

走査の完了を検知する仕組みを実装し、応答処理を1回にします。

追記)
「router で切り分け > dbコネクト > 走査」という実装ではないので、エラーでclient.close() されると、再接続されるのかな?という点も気になります。(追記ここまで


データの一覧は配列をJSONのstringデータで応答」という目標で、以下のような方法を思いつきます。

ご質問の big5db.js より

javascript

1 /* omitted */ 2 3 // 非同期の場合、カウント上限を取得しておく。 4 let foundItems = cursor.count(); 5 6 router.get('/',function(req,res,next){ 7 let datas = []; // 応答用の配列を準備 8 9 // データベース走査する cursor.forEach() 10 cursor.forEach( 11 function(doc) { 12 13 datas.push( Object.create(doc.personality) ); 14 15 // 非同期の場合、data.length でカウント 16 if( datas.length === foundItems ) { 17 res.status(200).json(datas); 18 } 19 20 }, 21 function(err) { 22 client.close(); 23 } 24 ); 25 // 同期であればこう? 26 //res.status(200).json(datas); 27 28 }); // router.get('/') 29 30 /* omitted */

Cursor Methods - MongoDB を参照しましたが、最新のコード実装までは追えていませんので、
上記コードは「答案」に過ぎませんが、解決の糸口になればと思います。

投稿2020/03/30 21:23

編集2020/03/30 21:31
AkitoshiManabe

総合スコア5434

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

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

masaking

2020/04/01 23:52

ありがとうございます。 何をループ処理の中に入れて、何を外に書くのか、コネクトからクローズの一連の流れは中で、レスポンスはその外に書く、ということを学びました。 ありがとうございます!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問