nodejs fs模块读取文件的路径问题

来源:互联网 发布:科比10总决赛数据 编辑:程序博客网 时间:2024/05/29 10:07

前言

相信绝大多数的前端和我一样都习惯用相对路径,因为在写前端代码的时候基本上都是用相对路径,而很少使用绝对路径,使用相对路径在当使用nodejs的fs模块读取文件时就有可能会给自己挖下这么一个坑(经典的nodejs的路径问题),问题如下:

问题

现在有一个demo,文件目录结构如下图:
目录结构
server.js的代码为:

let http = require('http');let fs = require('fs');let path = require('path');const PORT = 3000;// web页面的根路径// 注意:现在这里是相对路径let PUBLIC_PATH = '../public';http.createServer((req, res) => {    if (req.url === '/favicon.ico') {        res.end();        return;    }    let _path = '';    console.log(`请求路径为:${req.url}`);    if (req.url === '/') {        _path = PUBLIC_PATH + '/home.html';    }else {        _path = PUBLIC_PATH + req.url;    }    sendFile(res, _path);}).listen(PORT, () => {    console.log('Server listening on port 3000.');});function sendFile(res, path) {    fs.exists(path, (exist) => {        if (exist) {            fs.readFile(path, (err, file) => {                if (err) {                    send404(res);                } else {                    let mime = '';                    if (path.indexOf('.html')) {                        mime = 'text/html';                    }else if (path.indexOf('.js')) {                        mime = 'application/javascript';                    }                    res.writeHead(200, {'Content-type': `${mime};chartset=utf-8`});                    console.log('status : 200');                    res.end(file);                }            });        } else {            send404(res);        }    });}function send404(res) {    res.writeHead(404, {'Content-type': 'text/plain'});    console.log('status : 404');    res.end('404');}

注意这里是以相对路径去读写静态资源:

// web页面的根路径// 注意:现在这里是相对路径let PUBLIC_PATH = '../public';

然后以以下命令启动server.js并访问localhost:3000,打印结果为:
result
可以看到,正确访问到资源。
但是当以以下命令启动server.js并访问localhost:3000,打印结果为:
result
可以看到,无法访问到资源。
然后改变:

// web页面的根路径// 注意:现在这里是相对路径let PUBLIC_PATH = './public';

然后以以下命令启动server.js并访问localhost:3000,打印结果为:
result3
可以看到,正确访问到资源。
显而易见,fs模块读取文件的相对路径是以启动server.js的位置为基准的,而不是以server.js文件的位置
这就是这篇文章所要讲述的问题。

解决

很显然,启动脚本的方式可以有多种,所以nodejs官方推荐在使用fs模块读取文件时使用绝对路径,而不是相对路径。
改变:

// web页面的根路径// 注意:现在改为绝对路径let PUBLIC_PATH = path.resolve(__dirname, '../public');

经测试,无论在那个位置启动server.js都可以访问到静态资源。

路径

仍然以上面demo的目录结构(环境:window10;node v8.4.0),总结一些nodejs的常用路径:

    //获取node.exe的绝对路径    console.log(process.execPath);//D:\nodejs\node.exe    //存放当前文件(即server.js)文件夹的绝对路径    console.log(__dirname);//D:\nodeTest\node_path\lib    //当前文件(即server.js)的绝对路径    console.log(__filename);//D:\nodeTest\node_path\lib\server.js    //从所传入的文件路径(相对或绝对)中获取存放传入文件的文件夹的相对或绝对路径     //(例如 传入 public/home.html 则返回的是public)    console.log(path.dirname(__filename));//D:\nodeTest\node_path\lib    //执行当前脚本(即server.js)的位置 (例如 在根目录下执行 node ./xxx/xxx/a.js 则返回的是根目录地址 )    console.log(process.cwd());//D:\nodeTest\node_path\lib    //'a/b/c'和'../src' 组合而成的绝对路径 文件或文件夹都行    //例如 console.log(path.resolve('a/b/c', '../src'));//D:\nodeTest\node_path\lib\a\b\src    console.log(path.resolve(__dirname, '../public'));//D:\nodeTest\node_path\public    //'a/b/c'和'../src'组成的相对路径    //console.log(path.join('a/b/c', '../src'));//a\b\src    console.log(path.join(__dirname, '../public'));//D:\nodeTest\node_path\public    //相当于path.resolve(__dirname, '../public/home.html')或path.join(__dirname, '../public/home.html')    //但传入的必须是文件路径,而不是文件夹路径,而且当文件不存在时会抛出异常    console.log(require.resolve('../public/home.html'));//D:\nodeTest\node_path\public\home.html