0

我正在处理我的第一个 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
});
4

1 回答 1

0

您注释掉的代码返回 404 的原因是您正在通过path,而不是filePath每次都失败。

检查失败的原因fs.access()是它是一个异步调用 - 回调检查err不会立即发生。当该检查正在进行时,代码无条件地创建一个读取流到不存在的路径。(这也是为什么不推荐使用 fs.existsSync() 调用如果通过 filePath 可以解决问题。)

如果您想等到 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()使用fs.open(). 这样您就不会两次打开文件,也不会出现竞争条件。

于 2020-12-29T20:12:22.357 回答