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

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

ただいまの
回答率

87.90%

何度もDBにアクセスするとERR_EMPTY_RESPONSEエラーがでます。

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,037

score 3

コード

 前提・実現したいこと

ExpressとNode.jsとPostgreSQLで、掲示板Webページを開発しています。
以下のようになってしまいます。
質問の仕方が分かりずらいかもしれませんが、お力を貸してください。

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

何度かアクセス(ページを進めたり投稿したり…)を繰り返すと、

「localhostにアクセスしています」という文字がWebページ左下に出て止まり、先に進みません。
そしてしばらく待った後、

このページは動作していません
localhost からデータが送信されませんでした。
ERR_EMPTY_RESPONSE


と出てきて止まります。
原因がわかりません。

該当のソースコード

const express = require('express');
const router = express.Router();
const uuid = require('uuid');
const passwordHash = require('password-hash');
const pg = require('pg');
const isDebug = true


const pool = new pg.Pool({
  database: 'dashboard',
  user: 'postgres', 
  password: 'Kasumin1', 
  host: 'localhost',
  port: 5432,
});

(略)
//------------ ここから先はログイン済み---------------
router.all('/authed/*', async function (req, res, next) {
  console.log("/authed通過")
  console.log("req.cookies.token=" + req.cookies.token)
  let client = null
  let user = null
  let token = null
  // トークンチェック
  //DBアクセスする
  try{
    token = req.cookies.token
    if(!req.cookies.token)throw new Error(1)
    if(!pool)return res.redirect('/login?mag=5')
    client = await pool.connect()
    if(!client)throw new Error(5)
    user = await client.query('SELECT name FROM user_token WHERE token=$1;',[token])
    if(client){
    client.end()
    }
    if(!user.rows[0].name)throw new Error(1)
    req._local = {
      userInfo: {
        name: user.rows[0].name
      }
    }
  }catch(err){
    if(isDebug) console.log(err)
    msg = err.message
    if(client){
      client.end()
    }
    return res.redirect('/login?msg='+msg)
  }
  next()
})

//----------------------メインページ------------------------
router.get('/authed/dashboard',async function (req, res, next) {
  let posts = null
  let postnumber = 0
  let button = 0
  let msg = ""
  let page_count = 0
  let pageCount=null
  let client = null
  try{
    if (!req._local.userInfo.name)return res.redirect('/login?msg=1')

    if(!pool)throw new Error("DBアクセスに失敗しました。")
    client = await pool.connect()
    if(!client)throw new Error("DBアクセスに失敗しました。")

    //次へ・戻るボタンが押されたらページを変える
    if (req.query.page_count)page_count = +req.query.page_count

    //投稿ボタンが押された時のメッセージ
    if(req.query.msg == 'ok'){
      msg = "投稿が完了しました!"
    }else if(req.query.msg == 'ng'){
      msg = "投稿に失敗しました><"
    }



    pageCount = await client.query('SELECT * FROM board_posted ORDER BY number DESC OFFSET 10*$1;',[page_count])
    if(!pageCount.rowCount)throw new Error("まだ投稿がありません。")
    if (pageCount.rowCount <= 10) {
      button = 0
    } else {
      button = 1
    }

    //投稿一覧表示
    posts = await client.query('SELECT * FROM board_posted ORDER BY number DESC LIMIT 10 OFFSET 10*$1;',[page_count])
    if(!posts.rows)throw new Error("何もありません。")
    postnumber = await client.query('SELECT number FROM board_posted ORDER BY number DESC;')
    console.log("postnumber="+postnumber.rows[0].number)

  }catch(err){
    console.log("catchしました")
    msg = err.message
    if(client){
      client.end()
    }
    return res.redirect('/auther/dashboard?page_count='+page_count)
  }
  if(client){
    client.end()
  }
  res.render('dashboard', {
    username: req._local.userInfo.name,
    posts: posts.rows,
    button: button,
    page_count: page_count,
    msg: msg,
    postnumber: postnumber.rows[0].number
  });

});

//-------------------------投稿-------------------------
router.post('/newpost',async function (req, res, next) {
  console.log("req.cookies.token=" + req.cookies.token)
  let client = null
  let username=""
  let msg = ""
  let postnumber=+req.body.postnumber
  console.log("postnumber=" + postnumber)
  try{
    if(!pool)throw new Error("DBアクセスに失敗しました。")
    client = await pool.connect()
    if(!client)throw new Error()
    //例えばもし同時投稿などで44番目の投稿がすでにあったら、postnumberを45番にする
    number = await client.query('SELECT *FROM board_posted ORDER BY number DESC')
    if(number.rows[0].number == postnumber)postnumber++
    //投稿作業
    username = await client.query('SELECT name FROM user_token WHERE token=$1',[req.cookies.token])
    if(!username)throw new Error("usernameなかった")
    await client.query('INSERT INTO board_posted(number,name,text) VALUES($1,$2,$3)',[postnumber,username.rows[0].name,req.body.text])
    msg = "ok"
  }catch(err){
    console.log("catchしました")
    if(isDebug) console.log(err)
    msg = "ng"
    if(client){
      client.end()
    }
  }
  if(client){
    client.end()
  }
  res.redirect('/authed/dashboard?msg='+msg)
});

//次へボタンや戻るボタンが押されたら
router.post('/next', function (req, res, next) {
  let page_count
  try{
    page_count = Number(req.query.page_count)
  }catch(err){
    console.log("catchしました")
    return res.redirect('/authed/dashboard?page_count='+page_count)
  }
  res.redirect('/authed/dashboard?page_count=' + page_count)
})


module.exports = router;


// /authed/dahsboard?p=0
// 1ページあたりの表示件数 50件 (plen)

// OFFSET= p * plen LIMIST plen ORDER DESC
// 次へ /authed/dahsboard?p=(p+1)
// 前へ /authed/dahsboard?p=(p-1)
// (p+1) ページ目
<!DOCTYPE html>
<html>

<head>
  <title>Dashboard</title>
  <link rel='stylesheet' href='/stylesheets/style.css' />
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
        integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">

</head>

<body>
  <header>
    <div class="navbar navbar-dark bg-dark shadow-sm">
        <div class="container d-flex justify-content-between">
          <a class="navbar-brand d-flex align-items-center">
            <strong>Dashboard</strong>
          </a>
        </div>
    </div>

  </header>
  <br>
  <div class="card-deck">
    <!------------ユーザープロフィール------------->
    <div class="card" style="max-width: 18rem; max-height: 18rem;">
      <div class="card-header">your plofile</div>
        <div class="card-body">
          <h4 class="card-title"><%= username %></h4>
          <p class="card-text">
              This is where your introduction is written.
          </p>
        </div>
        <a href="/logout">logout</a>
      </div>

    <!------------ポストされた投稿一覧-------------->

  <div class="d-flex flex-column bd-highlight mb-3">
    <div class="row justify-content-center" style='color: red;'><%=msg%></div>
    <div style='color: red;'></div>
    <div class="border border-dark" style="padding:10px;background-color:#EEEEEE">
      <% if (posts != null) { %>
        <% for(var i= 0; i < posts.length; i++){ %>
                  <div class="card" style="width: 60rem;">
                    <%=posts[i].number%>
                  </div>
                  <div class="card-body">        
                      <table border="1">
                          <tbody>
                            <%=posts[i].text%>
                          <tr>
                              <td><%=posts[i].name%></td>
                          </tr>

                      </tbody>
                      </table>
                  </div>
          <%}%>
        <%}%>
    </div>
    <div class="d-flex">
      <% if(page_count >= 1){ %>
      <form  method="post" action="/next?page_count=<%-page_count -1%>">
          <button>戻る</button>
      </form>
      <% } %>
      <% if(button == 1){%>
      <form  method="post" action="/next?page_count=<%-page_count +1%>">
          <button>次へ</button>
      </form>
      <% } %>
    </div>
    <!--------------------投稿--------------------->
    <div class="p-2 bd-highlight">
      <form action="/newpost" method="post">
          <br>
          <div><input type="hidden" name="postnumber" value=<%-postnumber+1 %>><%=postnumber+1%>番目の投稿</div>
          <div>投稿文<br><textarea name="text" cols="50" rows="4" wrap="soft" required></textarea></div>
          <p>名前:<%=username%></p>
          <button type="submit">送信</button>
      </form>
    </div>
  </div>
</div>
</body> 
</html>

試したこと

変数clientをグローバル変数にする→qyery is not a functionエラーがでてできない。
変数clientをグローバル変数にしてawaitしてプログラムの初めでpool.connect()する→Cannot read property 'query' of undefinedのエラーがでる。

開発環境

windows10
VSCode
PostgreSQL
Node.js
JavaScript
Express

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

原因がわかりません。

Express のミドルウェアは 通常のコールバック関数を与えてください。
app/router が持つ use().all().get().post() といったミドルウェア登録用API の引数に注目

router.all('/authed/*', function middleware(req, res, next) { // 
  /* omitted */
})
router.get('/authed/dashboard', function middleware2(req, res, next) { // 
  /* omitted */
})
router.post('/newpost', function middleware3(req, res, next) { //
  /* omitted */
})

巡回機能に非同期関数(async関数)が指定されているため、正しく、next() done() を処理できず、ブラウザに対してサーバーエラーの応答もできなくなったのが原因と思います。

※ミドルウェアに async function を与える、KoaJS というフレームワークもあります。


DBアクセスなど 非同期実装 が必要な場合は

  1. ミドルウェア関数内のスコープ
  2. Moduleスコープ(グローバルに見えますが Module内に限って有効なスコープ)
  3. globalスコープ(NodeJS で Global オブジェクトのプロパティ)

に実装する必要があります。

  1. 別途ユーザ関数を定義
  2. ユーザモジュールを読み込む

掲示板Webページ

Express の修学目的であれば、DB代わりに OSのファイルシステムを使い、
「Expressの実装をコードリーディングして学ぶ」ことに注力するのも有りだと思います。
fs には同期/非同期のAPIが揃っていますし、ストレージ部分を手軽に実装できます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/06/09 22:12

    素早くわかりやすいご回答ありがとうございます。

    ご回答の通りに実装しなおしたうえで、const poolをローカル関数で定義するようにしたら、正常に動作しました!

    お時間を割いていただきありがとうございましたm(- -)m

    キャンセル

  • 2020/06/09 22:13

    修学のアドバイスも、ありがとうございます!

    キャンセル

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

  • ただいまの回答率 87.90%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る