1. 程式人生 > >Nodejs之靜態資源處理

Nodejs之靜態資源處理

前言

剛開始用Nodejs寫簡單的web伺服器的時候,總是感覺少了點什麼。

原來,我一直是在頁面上輸出什麼Hello World!啊, It Works.之類的了。還確實沒有處理關於CSSJS這些引用的靜態相關的資源。

一開始覺得處理這些東西應該會非常的easy,結果發現不僅僅是這麼回事。途中也遇到了一些人們經常可能會犯的想當然的錯誤。於是我就決定好好的記錄一下關於Nodejs中對於靜態資源的處理。

著眼於問題

重現問題

先來展示一下目錄結構吧。

E:\CODE\NODEJS\LEARN\WEB\EXPRESS-STATIC
│  server.js
│
├─html
│      index.html
│
└─public
    ├─css
    │      index.css
    │
    ├─imgs
    │      1.gif
    │
    └─js
            index.js

這樣一個web專案的骨架就算是搭建好了。下面簡單的使用nodejs的http模組實現一個web伺服器。目標就是顯示index.html

index.html

<html>
    <head>
        <meta charset="UTF-8">
        <title>My Index Page</title>
        <link rel="stylesheet" href="/public/css/index.css">
    </head>
    <body>
        <h1
>
It Works.</h1> <hr> <img src="/public/imgs/1.gif" /> </body> </html>

index.css

* {
    padding: 0px;
    margin: 0px;
}

h1 {
    color: yellowgreen;
}

body {
    background-color: #2C001E;
}

server.js

var http = require('http');
var fs = require
('fs'); function handle_request(req, res) { // 客戶端對伺服器的請求,說白了就是對相關檔案內容的請求。 res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(get_file_content(__dirname + '\\' + 'html' + '\\' + 'index.html')); } function get_file_content(filepath) { return fs.readFileSync(filepath); } var server = http.createServer(handle_request); server.listen(8080);

程式碼中用到了一個名為__dirname的變數,其值就是當前執行檔案的絕對路徑。通過它,我們可以組裝出我們想要獲取的檔案的全路徑。

執行程式碼,開啟伺服器。

node server.js

發現問題

然後我們開啟瀏覽器,會發現這樣的景象。
沒有任何效果的頁面

不僅是CSS樣式沒顯示出來,就連圖片也同樣沒有正確顯示。

然後我們開啟瀏覽器控制檯,會發現客戶端向伺服器傳送了3次請求,分別是:
客戶端請求內容

  • localhost: HTML內碼表
  • index.css: 樣式檔案
  • 1.gif: 圖片檔案

之所以我們沒能看到具體的效果,就是因為伺服器沒有正確返回相關的內容啊。這樣一想,一下子就恍然大悟了。所以這顆Silver Bullet就是

針對每一個不同的資源請求,正確的返回相關的內容。

解決問題

我的思路:

  • 剖析request請求地址。分割出檔名,字尾名。
  • 根據字尾補全相關檔案在檔案系統中的全路徑。
  • 根據全路徑讀取內容,返回給客戶端。

server.js

然後簡單的修改了一下server.js,當然這裡也只是簡單的做下示意,生產程式碼可千萬不要這麼寫。

var http = require('http');
var fs = require('fs');


function handle_request(req, res) {

    // 不管是什麼請求,對檔案的請求的話,應該是針對字尾名進行內容讀取發放。
    var suffix = req.url.substr(req.url.length - 4, req.url.length);
    var realpath = __dirname + '\\' + 'public' + '\\';
    var filename = req.url.substr(req.url.length - 9);
    if (suffix === '.css') {
        res.writeHead(200, { 'Content-Type': 'text/css' });
        res.end(get_file_content(realpath + '\\css\\' + filename));
    } else if (suffix === '.gif') {
        res.writeHead(200, {'Content-Type': 'image/gif'});
        res.end(get_file_content(realpath+'\\imgs\\1.gif'));
    } else {
        res.writeHead(200, { 'Content-Type': 'text/html' });
        res.end(get_file_content(__dirname + '\\' + 'html' + '\\' + 'index.html'));
    }
}

function get_file_content(filepath) {
    return fs.readFileSync(filepath);
}

var server = http.createServer(handle_request);
server.listen(8080);

然後重啟伺服器。

node server.js

再次訪問瀏覽器

http://localhost:8080

如下:
靜態資源正確訪問

因為沒有錄屏,所以沒體現出GIF圖的效果,不過關於靜態資源已經足夠顯示了。

express

還有一個比較好用的web框架,express,其對於靜態資源的支援更加方便。屬於一個更加高層的封裝。

核心

通過express物件的app.use(express.static(folder_path))方法就可以了。方法的引數指定為相關的靜態資原始檔夾路徑即可。

server-express.js

/**
 * 使用express來實現對於靜態資源的控制。
 */
let express = require('express');
let fs = require('fs');
let path = require('path');


var app = express();

app.use(express.static(path.join(__dirname, './public')));

app.all('/', function(req, res){
    console.log("=======================================");
    console.log("請求路徑:"+req.url);
    var filename = req.url.split('/')[req.url.split('/').length-1];
    var suffix = req.url.split('.')[req.url.split('.').length-1];
    console.log("檔名:", filename);
    if(req.url==='/'){
        res.writeHead(200, {'Content-Type': 'text/html'});
        res.end(get_file_content(path.join(__dirname, 'html', 'index.html')));
    }else if(suffix==='css'){
        res.writeHead(200, {'Content-Type': 'text/css'});
        res.end(get_file_content(path.join(__dirname, 'public', 'css', filename)));
    }else if(suffix in ['gif', 'jpeg', 'jpg', 'png']) {
        res.writeHead(200, {'Content-Type': 'image/'+suffix});
        res.end(get_file_content(path.join(__dirname, 'public', 'images', filename)));
    }
});


function get_file_content(filepath){
    return fs.readFileSync(filepath);
}

app.listen(8080);

index.html

因為剛才使用了靜態資源控制,也就是說我們可以簡化HTML頁面中對於靜態資源的路徑拼寫。比如:

原來在HTML頁面中要這麼寫:

<img src='/public/images/1.gif' />

現在只需要這麼寫了:

<img src='/images/1.gif' />

看起來就是少了個 /public, 但是實際上通過這一點就可以表明express 其實幫我們省去了很多枯燥的工作內容。

然後開啟瀏覽器就可以看到具體的靜態資源內容了。
express控制靜態資源

那麼對於不同的圖片型別的支援程度如何呢?
下面修改一下HTML頁面:

<html>
    <head>
        <meta charset="UTF-8">
        <title>My Index Page</title>
        <link rel="stylesheet" href="/css/index.css">
    </head>
    <body>
        <h1>It Works.</h1>
        <hr>
        <img src="/images/1.gif" /><br>
        <img src="/images/2.jpg" alt=""><br>
        <img src="/images/3.png" alt=""><br>
    </body>
</html>

開啟瀏覽器檢視對於gif, png, jpg的支援如何?
針對不同型別圖片的支援

總結

經過了這些個嘗試,從發現問題,到解決問題的整個過程,其實還是很讓人興奮的。其實,程式設計也是這麼個道理:

要敢於面對它,然後吃掉它。