前言
相信绝大多数的前端和我一样都习惯用相对路径,因为在写前端代码的时候基本上都是用相对路径,而很少使用绝对路径,使用相对路径在当使用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,打印结果为:
可以看到,正确访问到资源。
但是当以以下命令启动server.js并访问localhost:3000,打印结果为:
可以看到,无法访问到资源。
然后改变:
// web页面的根路径
// 注意:现在这里是相对路径
let PUBLIC_PATH = './public';
然后以以下命令启动server.js并访问localhost:3000,打印结果为:
可以看到,正确访问到资源。
显而易见,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