Haniwa820
@Haniwa820

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

NodeJSでページ遷移をしたい! (HTTP)

解決したいこと

フォームの内容に不備があったとき、その旨を伝えるページに遷移させたい。

Node.jsで簡易なWebサイトを作成しています。
フォームから送信された内容をPOST通信をして、クエリ解析をするところまでは調べながらできたのですが、正規表現で一致しなかった場合に別のページに遷移させるというところがどうしてもできません。お力添えお願いします(;´・ω・)
また、他に改善できるところがあればご教授いただけると嬉しいです。

環境

Windows 10
NodeJS ver 10.1.0

前提条件

ローカルで作業しています。セキュリティ面に関しては大目に見てくださいm(_ _)m
Expressで実装することも試しましたが、うまくいかなかった為HTTPサーバーで実装したいです。

発生している問題・エラー

node:_http_server:345
    throw new ERR_HTTP_HEADERS_SENT('write');
    ^

Error [ERR_HTTP_HEADERS_SENT]: Cannot write headers after they are sent to the client
    at new NodeError (node:internal/errors:406:5)
    at ServerResponse.writeHead (node:_http_server:345:11)
    at IncomingMessage.<anonymous> (C:\URL省略\main.js:101:30)
    at IncomingMessage.emit (node:events:526:35)
    at endReadableNT (node:internal/streams/readable:1408:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {

または、問題・エラーが起きている画像をここにドラッグアンドドロップ

該当するソースコード

const http = require("http");
const port = 3000;
const fs = require('fs');
const mysql = require('mysql2');
const qs = require('qs');

const topPage = fs.readFileSync('./index.html', 'UTF-8');
const server = http.createServer(Routing);

server.listen(port);
console.log(`The server is runnning on port number: ${port}`);

const connection = mysql.createConnection ({
    host: "", //省略
    user: "",
    password: "",
    database: ""
});
   
connection.connect((error) => {
    if (error) {
      console.error('connection to DB error: ' + error);
      return;
    }
    console.log('connection to DB success: ' + error);
});

function Routing (request, response) {
    switch(request.url) {
        case '/':
        case '/index.html':
            response.writeHead(200, {'Content-Type': 'text/html'});
            response.write(topPage);
            response.end();
            break;
        case '/index.css':
            response.writeHead(200, {'Content-Type': 'text/css'});
            response.write(fs.readFileSync('./index.css', 'UTF-8'));
            response.end();
            break;
        case '/register/index.html':
            response.writeHead(200, {'Content-Type': 'text/html'});
            response.write(fs.readFileSync('./register/index.html', 'UTF-8'));
            response.end();
            break;
        case '/register/register.css':
            response.writeHead(200, {'Content-Type': 'text/css'});            
            response.write(fs.readFileSync('./register/register.css', 'UTF-8'));
            response.end();
            break;
        case '/failed/index.html':
            response.writeHead(200, {'Content-Type': 'text/html'});
            response.write(fs.readFileSync('./failed/index.html', 'UTF-8'));
            response.end();
            break;
        case '/failed/failed.css':
            response.writeHead(200, {'Content-Type': 'text/css'});            
            response.write(fs.readFileSync('./failed/failed.css', 'UTF-8'));
            response.end();
            break;
        case '/login/index.html':
            response.writeHead(200, {'Content-Type': 'text/html'});
            response.write(fs.readFileSync('./login/index.html', 'UTF-8'));
            response.end();
            break;
        case '/login/login.css':
            response.writeHead(200, {'Content-Type': 'text/css'});
            response.write(fs.readFileSync('./login/login.css', 'UTF-8'));
            response.end();
            break;
        default:
            response.writeHead(200, {'Content-Type': 'text/html'});
            response.write(topPage);
            response.end();
            break;
    }

    if(request.method === 'GET') {

    }

    if(request.method === 'POST') {
        var data = '';
        request.on('data', (chunk) => {
            data += chunk
        }).on('end', () => {
            const obj = qs.parse(data);
            console.log(data);
            //console.log(obj);
            
            if(/grade=.*&class=.*&name=.*&number=[0-9]*&gmail=.*/.exec(data) !== null) {
                if(/省略/.exec(obj.name) !== null && 
                    /省略/.exec(obj.number) != null && 
                    /省略/.exec(obj.gmail) != null) { 
                    console.log("clear");
                } else {
                    console.log ("failed");
                    response.writeHead(200, {'Content-Type': 'text/css'}); //ここでエラーが発生
                    response.end()
                }

                //const sql = "INSERT INTO username values(\""+ obj.name + "\", " + obj.number + ", \"" + obj.gmail + "\")" 
                //connection.query(sql, (error, result) => {
                //    if(error) {
                //        console.error('insert to DB error: ' + error);
                //        return;
                //    }
                //    console.log('success:' + result);
                //})
            } else if(/user=.*&pass=.*/.exec(data) !== null) {
                const sql = "SELECT * FROM admin";
                connection.query(sql, (error, result) => {
                    if(error){
                        console.error('select from DB error: ' + error);
                        return;
                    } 
                    console.log('success: ' + result);
                })
                console.log("branch 2");
            }
        });
    }
};

自分で試したこと

1 そもそも記述を消してみる → TOPページに遷移してしまう
2 URLを格納する変数を用意して、最後にファイルを読み込む → 失敗

0

1Answer

Cannot write headers after they are sent to the client

ヘッダーを送信した後に書き込むことが出来ないというエラーです。

This method must only be called once on a message and it must be called before response.end() is called.

node.js公式ドキュメントの引用です。
どうやらresponse.writeHeadメソッドは一度しか呼べないようです。

Routingメソッドの最初にswitch文でresponse.writeHeadを呼んでendメソッドで閉じたのに、後から書き込むことは出来ませんよっていうことですね。
一度だけ呼ぶように変更しましょう。

あと気になったのが以下の部分でtext/cssを指定していますが、別のページに遷移させたいのならtext/htmlにするのではないでしょうか

else {
                    console.log ("failed");
                    response.writeHead(200, {'Content-Type': 'text/css'});
                    response.end()
                }
0Like

Comments

  1. @Haniwa820

    Questioner

    解答ありがとうございます!
    実はこの質問を投稿してから暫く自分で試行錯誤していたところ、つい先日できまして、まさに @ebaeba_st さんの言った通り、writeheadは一度しか呼び出せないようでしたので、POST通信の時に呼び出さないことで回避できました!
    ちなみに、text/cssになっていたのはそもそも関数が上手くいっていなかったために私が気付かなかっただけです…(´・ω・`)
    今はちゃんとtext/htmlになっています!

Your answer might help someone💌