Почему мой сервер my nodejs выходит из строя, даже если я обрабатываю предполагаемую ошибку, которая возникает?

#javascript #node.js

#javascript #node.js

Вопрос:

Я работаю над своим первым примером сервера nodejs, и он в основном работает. Однако я заметил, что сервер выйдет из строя, если я попытаюсь вызвать несуществующий HTML-файл. Мне удалось найти обходной путь (который был закомментирован), но мне очень любопытно, почему исходный код не вел себя так, как я ожидал. Перед сбоем я бы увидел желаемый ответ, а затем произошел сбой сервера со следующим выводом:

 Server running at http://localhost:3000
Request for /aboutuss.html by method GET
ENOENT: no such file or directory, access '/Users/albertkhasky/NodeJS/node-http/public/aboutuss.html'
events.js:173
      throw er; // Unhandled 'error' event
      ^

Error: ENOENT: no such file or directory, open '/Users/**********/NodeJS/node-http/public/aboutuss.html'
Emitted 'error' event at:
    at fs.open (internal/fs/streams.js:117:12)
    at FSReqCallback.args [as oncomplete] (fs.js:145:20)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
 

Вот код:

 const http = require('http');
const fs = require('fs');
const path = require('path');

const hostname = 'localhost'
const port = 3000;

const server = http.createServer((req, res) => {
    console.log("Request for "   req.url   ' by method '   req.method);


    if(req.method == 'GET'){
        var fileUrl;
        if(req.url == '/'){
            fileUrl = '/index.html';
        }else{
            fileUrl = req.url;
        }
        var filePath = path.resolve('./public'   fileUrl);
        const fileExt = path.extname(filePath);
        if(fileExt == '.html'){

            // if (!fs.existsSync(path)) {
            //     res.statusCode = 404;
            //     res.setHeader('Content-Type', 'text/html');
            //     res.end('<html><body><h1>Error: 404 '   fileUrl    ' HTML FILE NOT FOUND </h1></body></html>');
            //     return;
            // }

            fs.access(filePath, fs.F_OK, (err) => {
                if(err){
                    res.statusCode = 404;
                    res.setHeader('Content-Type', 'text/html');
                    res.end('<html><body><h1>Error: 404 '   fileUrl    ' HTML FILE NOT FOUND </h1></body></html>');
                    console.log(err.message);
                    return;
                }
            })
        }else{
            res.statusCode = 404;
            res.setHeader('Content-Type', 'text/html');
            res.end('<html><body><h1>Error: 404 '   fileUrl    ' none HTML file not found</h1></body></html>');
            return;
        }
        res.statusCode = 200;
        res.setHeader('Content-Type', 'text/html');
        fs.createReadStream(filePath).pipe(res);
    
    }else{
        res.statusCode = 404;
        res.setHeader('Content-Type', 'text/html');
        res.end('<html><body><h1>Error: 404 '   req.method    ' not supported</h1></body></html>');
        return;
    }

});

server.listen(port, hostname, () => {
    console.log(`Server running at http://${hostname}:${port}`); //variables inside the string is the reason for backticks
});
 

Ответ №1:

причина, по которой ваш закомментированный код возвращает значение 404, заключается в том, что вы передаете path , а не filePath в том, что он каждый раз терпит неудачу.

причина, по которой ваша fs.access() проверка завершается неудачей, заключается в том, что это асинхронный вызов — проверка обратного err вызова выполняется не сразу. во время выполнения этой проверки код безоговорочно создает поток чтения для несуществующего пути. (это также причина, по которой устаревший вызов fs.existsSync() решил бы проблему, если бы был передан путь к файлу.)

если вы хотите дождаться выполнения вызова fs.access, переместите успешный возврат (где вы создаете поток чтения) в обратный вызов fs.access после проверки ошибки, например:

     fs.access(filePath, fs.F_OK, (err) => {
        if(err){
            res.statusCode = 404;
            res.setHeader('Content-Type', 'text/html');
            res.end('<html><body><h1>Error: 404 '   fileUrl    ' HTML FILE NOT FOUND </h1></body></html>');
            console.log(err.message);
            return;
        }
        res.statusCode = 200;
        res.setHeader('Content-Type', 'text/html');
        fs.createReadStream(filePath).pipe(res);
    })
 

более эффективным способом выполнения операции было бы использовать fs.open() для файла, обработать возврат ошибки, а затем fs.createReadStream() использовать fd, возвращаемый fs.open() . таким образом, вы не открываете файл дважды и не допускаете возможности возникновения условий гонки.

Комментарии:

1. Спасибо за вашу помощь. Чего я не понимаю, так это почему код возвращает ожидаемый ответ, но затем сразу же завершается сбоем. Если я понимаю ваше объяснение, оно должно завершиться немедленно, без каких-либо выходных данных. Почему это работает только один раз? Кроме того, перемещение успешного возврата не изменяет поведение, которое я описал

2. можете ли вы предоставить / обновить свой код? если вы переместили возврат (т. Е. Удалили Исходный createReadStream() и получили его только при успешном fs.access() вызове, я не понимаю, как это может быть ошибкой в открытом потоке. этого не должно произойти.

3. также небольшое замечание — вы захотите использовать, fs.R_OK а не fs.F_OK потому, что хотите, чтобы файл был читаемым.

4. черт возьми, я просто изменил код (переместив код, начинающийся с res.statusCode = 200; и заканчивающийся fs.createReadStream(filePath).pipe(res); на после if (err) { блока, и сервер не вылетает для меня. может быть, вы можете добавить свой измененный код в свой пост?

5. Я понимаю, что я делал неправильно. У меня была эта строка в 2 местах: fs.createReadStream(filePath).pipe (res); Еще раз, большое спасибо за ваше руководство!