天天看點

nodejs fs子產品讀取檔案的路徑問題

前言

相信絕大多數的前端和我一樣都習慣用相對路徑,因為在寫前端代碼的時候基本上都是用相對路徑,而很少使用絕對路徑,使用相對路徑在當使用nodejs的fs子產品讀取檔案時就有可能會給自己挖下這麼一個坑(經典的nodejs的路徑問題),問題如下:

問題

現在有一個demo,檔案目錄結構如下圖:

nodejs fs子產品讀取檔案的路徑問題

server.js的代碼為:

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

// 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(, {'Content-type': `${mime};chartset=utf-`});
                    console.log('status : 200');
                    res.end(file);
                }
            });
        } else {
            send404(res);
        }
    });
}

function send404(res) {
    res.writeHead(, {'Content-type': 'text/plain'});
    console.log('status : 404');
    res.end('404');
}
           

注意這裡是以相對路徑去讀寫靜态資源:

// web頁面的根路徑
// 注意:現在這裡是相對路徑
let PUBLIC_PATH = '../public';
           

然後以以下指令啟動server.js并通路localhost:3000,列印結果為:

nodejs fs子產品讀取檔案的路徑問題

可以看到,正确通路到資源。

但是當以以下指令啟動server.js并通路localhost:3000,列印結果為:

nodejs fs子產品讀取檔案的路徑問題

可以看到,無法通路到資源。

然後改變:

// web頁面的根路徑
// 注意:現在這裡是相對路徑
let PUBLIC_PATH = './public';
           

然後以以下指令啟動server.js并通路localhost:3000,列印結果為:

nodejs fs子產品讀取檔案的路徑問題

可以看到,正确通路到資源。

顯而易見,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