利用connect創建前端開發服務器

對於先後端徹底分離的系統,開發時候咱們須要給前端配置服務器,固然咱們能夠選擇Nginx之類的服務器進行配置,但咱們也能使用NodeJS構建高自由度的前端開發服務器。javascript

 

簡單靜態服務器

下面是一個簡單的靜態服務器:css

var http = require('http'), 
    url = require('url'),
    fs = require('fs')
    path = require('path');

function getContentType(_path){ 
    var contentType, 
        ext = path.extname(_path); 

    switch(ext){ 
        case '.html':
        case '.htm':
            contentType = 'text/html'; 
            break; 
        case '.js':
            contentType = 'text/javascript'; 
            break; 
        case '.css':
            contentType = 'text/css';
            break;
        case '.gif':
            contentType = 'image/gif';
            break; 
        case '.jpg':
            contentType = 'image/jpeg'; 
            break;
        case '.png': 
            contentType = 'image/png'; 
            break; 
        case '.ico':
            contentType = 'image/icon'; 
            break;
        default:
            contentType = 'application/octet-stream'; 
    } 
    
    return contentType; 
}

function httpService(req, res){ 
    var reqUrl = req.url,
        pathName = url.parse(reqUrl).pathname,
        filePath;

    if(Path.extname(pathName) === ""){ 
        pathName += "/";
    } 
    if(pathName.charAt(pathName.length - 1) === "/"){ 
        pathName += "index.html";
    } 

    filePath = path.join('./', pathName);  
    fs.exists(filePath, function(exists){ 
        if(exists){
            res.writeHead(200, {'Content-Type': getContentType(filePath)});  
            var stream = fs.createReadStream(filePath, {flags : "r", encoding : null}); 
                stream.on('error', function(){ 
                    res.writeHead(404);
                    res.end('<h1>404 Read Error</h1>');
            });
            stream.pipe(res); 
        }else{
            res.writeHead(404, {'Content-Type': 'text/html'}); 
            res.end('<h1>404 Not Found</h1>'); 
        } 
    }); 

}

var webService = http.createServer(httpService);
webService.on('error', function(error){ 
    console.log('[WebService][error] ' + error);
}); 
webService.listen(300, function(){ 
    console.log('[WebService][Start] running at http://127.0.0.1:' + 3000 + '/'); 
});

能夠發現一個靜態服務器也要寫不少行代碼才能完成,可是若是咱們使用connect,會發現這一切只要幾行代碼。html

 

Connect?

connect是高性能NodeJS Web中間件框架,提供了二十餘箇中間件,並有衆多第三方中間件支持。connect使用很是簡單,例如上面的靜態服務器,在connect中只需:前端

var connect = require('connect');

var app = connect()
    .use(connect.static('public'))
    .listen(3000);

 

安裝connect

咱們只要在命令行中輸入:java

npm install connectweb

即可以安裝了。npm

 

模型

connect的模型很是簡單,經過use註冊中間件,每一箇中間件接收request和response,若是發現request是該中間件處理的,那麼處理完後經過response.end輸出,不然經過next交給下一個中間件處理。json

 

需求

OK,如今咱們看看需求是怎樣的:後端

  • 因爲先後端是分離的,因此開發的時候先後端也是分離的,那麼前端和後端作交互就會跨域,因此首先要能反向代理到後端。
  • 能夠簡單配置靜態服務器(咱們假設前端的文件全是靜態的)。
  • 能夠在前端模擬數據交互,也就是在特定的文件夾存儲模擬的數據,而後對應返回。
  • 力求簡便,經過json配置。

 路徑結構:跨域

/static:靜態服務路徑與後端交互

/prototype/static:原型路徑與模擬數據交互

/prototype/static/mockup-data/:模擬數據路徑

 

代碼

static.js:

module.exports = (function(){
    "use strict"
    var connect = require('connect'),
        http = require('http'),
        url = require('url'),
        path = require('path'),
        proxy = require('proxy-middleware'),
        fs = require('fs'),
        pkg = JSON.parse(fs.readFileSync('./package.json'));

    // 經過後綴名獲得content type
    function _getType(extname){
        switch(extname){
            case '.json':
                return 'application/json';
            case '.xhtml':
            case '.html':
                return 'text/html';
            default:
                return 'application/json';
        }
    }

    // 使用connect
    var app = connect()
        // 使用logger中間件
        .use(connect.logger('dev'))
        // 用static中間件處理靜態服務
        .use(pkg.static.path, connect.static(pkg.static.root, {maxAge: pkg.maxAge}))
        .use(pkg.prototype.path + '/static/mockup-data', function(req, res, next){
            // 若是是GET方法,交由下面的中間件處理
            if(req.method === 'GET') return next();

            var urlObj = url.parse(pkg.prototype.root + req.originalUrl.replace(pkg.prototype.path, '')),
                filePath = urlObj.protocol + urlObj.pathname,
                contentType = _getType(path.extname(urlObj.pathname)),
                method = req.method.toLowerCase(),
                // 獲得與方法名對應的模擬文件路徑,例如原來文件路徑是1.json,在POST方法中變成1.post.json
                methodFilePath = filePath.replace(/(\.xhtml|\.html|\.json)$/, '.' + method + '$1');

            fs.exists(methodFilePath, function(exist){
                // 若是方法名對應的模擬文件存在
                if(exist){
                    // 替換文件路徑
                    filePath = methodFilePath;
                }
                // 讀取文件
                fs.readFile(filePath, function(err, data){
                    if(err) return next(err);
                    res.writeHead(200, {'Content-Type': contentType});
                    res.statuCode = 200;
                    res.end(data);
                });
            });
        })
        // 用static中間件處理原型的靜態服務
        .use(pkg.prototype.path, connect.static(pkg.prototype.root, {maxAge: pkg.maxAge}))
        // 使用proxy-middleware中間件進行反向代理
        .use(proxy(url.parse(pkg.proxy)))
        .listen(pkg.port, function(){console.log('Connect with: http://127.0.0.1:' + pkg.port)});
})();

package.json:

{
    "maxAge": 3600,
    "port": 80,
    "proxy": "http://192.168.10.202:8080",
    "prototype": {
        "path": "/prototype",
        "root": "C:/Users/Desktop/manggis/manggis_web/src/main/webapp/prototype"
    },
    "static": {
        "path": "/manggis_web/static", 
        "root": "C:/Users/Desktop/manggis/manggis_web/src/main/webapp/static"
    },
    "devDependencies": {
        "connect": "~2.8.4",
        "proxy-middleware": "~0.4.0"
    }
}
相關文章
相關標籤/搜索