NodeJS專案基礎結構簡單介紹

tankII發表於2021-09-09

圖片描述

新建的基於ejs模版的NodeJS專案.png

按照常規,去執行npm start

圖片描述

側邊欄左下角的npm命令.png

或者在Terminal中手動輸入命令,結果如下:

C:Subversiontest>npm start

> test@0.0.0 start C:Subversiontest> node ./bin/www

可以看到是執行了test/package.json檔案中的start命令,初始packagejson.json檔案內容如下:

{  "name": "test",  "version": "0.0.0",  "private": true,  "scripts": {    "start": "node ./bin/www"
  },  "dependencies": {    "cookie-parser": "~1.4.3",    "debug": "~2.6.9",    "ejs": "~2.5.7",    "express": "~4.16.0",    "http-errors": "~1.6.2",    "morgan": "~1.9.0"
  }
}

執行start,對應的命令為node ./bin/www並在命令列執行。現在專案已經啟動成功了,可以開啟瀏覽器輸入localhost:3000檢視一下,但是本次側重點在於專案啟動時候發生的完整的過程。所以……

那麼我們需要看一下 ./bin/www 檔案

#!/usr/bin/env node/**
 * Module dependencies.
 */var app = require('../app');var debug = require('debug')('test:server');var http = require('http');/**
 * Get port from environment and store in Express.
 */var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);/**
 * Create HTTP server.
 */var server = http.createServer(app);/**
 * Listen on provided port, on all network interfaces.
 */server.listen(port);
server.on('error', onError);
server.on('listening', onListening);/**
 * Normalize a port into a number, string, or false.
 */function normalizePort(val) {  var port = parseInt(val, 10);  if (isNaN(port)) {    // named pipe
    return val;
  }  if (port >= 0) {    // port number
    return port;
  }  return false;
}/**
 * Event listener for HTTP server "error" event.
 */function onError(error) {  if (error.syscall !== 'listen') {    throw error;
  }  var bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;  // handle specific listen errors with friendly messages
  switch (error.code) {    case 'EACCES':      console.error(bind + ' requires elevated privileges');
      process.exit(1);      break;    case 'EADDRINUSE':      console.error(bind + ' is already in use');
      process.exit(1);      break;    default:      throw error;
  }
}/**
 * Event listener for HTTP server "listening" event.
 */function onListening() {  var addr = server.address();  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
}

透過 require() 來引入本地安裝的包,這裡載入了三個包 app、debug 、http ,主要關注一下app.js

var createError = require('http-errors');var express = require('express');var path = require('path');var cookieParser = require('cookie-parser');var logger = require('morgan');var indexRouter = require('./routes/index');var usersRouter = require('./routes/users');var app = express();// view engine setupapp.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);// catch 404 and forward to error handlerapp.use(function(req, res, next) {
  next(createError(404));
});// error handlerapp.use(function(err, req, res, next) {  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

可以看到app載入的為該專案基礎元件,核心為 var app = express(); 看一下express.js

var bodyParser = require('body-parser')var EventEmitter = require('events').EventEmitter;var mixin = require('merge-descriptors');var proto = require('./application');var Route = require('./router/route');var Router = require('./router');var req = require('./request');var res = require('./response');/**
 * Expose `createApplication()`.
 */exports = module.exports = createApplication;/**
 * Create an express application.
 *
 * @return {Function}
 * @api public
 */function createApplication() {  var app = function(req, res, next) {
    app.handle(req, res, next);
  };

  mixin(app, EventEmitter.prototype, false);
  mixin(app, proto, false);  // expose the prototype that will get set on requests
  app.request = Object.create(req, {    app: { configurable: true, enumerable: true, writable: true, value: app }
  })  // expose the prototype that will get set on responses
  app.response = Object.create(res, {    app: { configurable: true, enumerable: true, writable: true, value: app }
  })

  app.init();  return app;
}/**
 * Expose the prototypes.
*/exports.application = proto;
exports.request = req;
exports.response = res;/**
 * Expose constructors.
 */exports.Route = Route;
exports.Router = Router;/**
 * Expose middleware
 */exports.json = bodyParser.json
exports.query = require('./middleware/query');
exports.static = require('serve-static');
exports.urlencoded = bodyParser.urlencoded

將app用到的中介軟體等暴露出來,所以 app = express() 實際上就是載入應用基礎元件,生成專案的根節點(當然這個節點是複合的)。所以在app.js中,進行的是載入應用基礎元件並進行應用設定初始化(包含了檢視目錄設定、頁面模板引擎設定、中介軟體的設定、靜態資源目錄設定以及錯誤捕捉相關內容)。

繼續回到 ,同樣將debug配置、http相關元件進行載入。繼而是預設埠號的設定。透過http.createServer(app),建立應用服務相關資訊,並對埠進行監聽。

瀏覽器輸入localhost:3000

圖片描述

express框架專案跑起來了.png

控制檯顯示:

GET / 304 3.389 ms - -
GET /stylesheets/style.css 304 0.680 ms - -

說明在以GET方式請求URI為"/"的資源,並以GET方式請求/stylesheets/style.css資源,這個發生在app.js中我們設定的資源請求。

var indexRouter = require('./routes/index');var usersRouter = require('./routes/users');

app.use('/', indexRouter);
app.use('/users', usersRouter);

我們來看下 ./routes/index 檔案

var express = require('express');var router = express.Router();/* GET home page. */router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});module.exports = router;

即定義網站主頁的路由

使用 express.Router 類建立模組化、可掛載的路由控制程式碼(簡稱:路由模組)。Router 例項是一個完整的中介軟體和路由系統。最終,在應用中載入路由模組app.use('/', indexRouter);

透過 res.render 對檢視進行渲染,上述為對index.ejs的渲染。ps:在app.js中已經設定了views的所在目錄。語法:res.render(view [,locals] [,callback])

  • locals 定義檢視的區域性變數。區域性變數cache啟用檢視快取。將其設定為true,以在開發期間快取檢視; 預設情況下,生產中啟用了檢視快取。

  • callback 定義回撥函式。如果存在,則該方法返回可能的錯誤和異常資訊,將不執行自動相應。發生錯誤時,該方法在next(err)內部呼叫

示例:

// send the rendered view to the clientres.render('index');// if a callback is specified, the rendered HTML string has to be sent explicitlyres.render('index', function(err, html) {
  res.send(html);
});// pass a local variable to the viewres.render('user', { name: 'Tobi' }, function(err, html) {  // ...});

圖片描述

res響應方法.png


區別:路由控制程式碼

為請求處理提供多個回撥函式,其行為類似 。唯一的區別是這些回撥函式有可能呼叫 next('route') 方法跳至下一個同路由的回撥函式而略過其他路由回撥函式。路由控制程式碼有多種形式,可以是一個函式、一個函式陣列,或者是兩者混合。

使用一個回撥函式處理路由:

app.get('/example/a', function (req, res) {
  res.send('Hello from A!');
});

使用多個回撥函式處理路由(記得指定 next 物件):

app.get('/example/b', function (req, res, next) {  console.log('response will be sent by the next function ...');
  next();
}, function (req, res) {
  res.send('Hello from B!');
});

使用回撥函式陣列處理路由:

var cb0 = function (req, res, next) {  console.log('CB0');
  next();
}var cb1 = function (req, res, next) {  console.log('CB1');
  next();
}var cb2 = function (req, res) {
  res.send('Hello from C!');
}
app.get('/example/c', [cb0, cb1, cb2]);

混合使用函式和函式陣列處理路由:

var cb0 = function (req, res, next) {  console.log('CB0');
  next();
}var cb1 = function (req, res, next) {  console.log('CB1');
  next();
}
app.get('/example/d', [cb0, cb1], function (req, res, next) {  console.log('response will be sent by the next function ...');
  next();
}, function (req, res) {
  res.send('Hello from D!');
});

區別:路由方法

一個路由示例:

var express = require('express');var app = express();// respond with "hello world" when a GET   request is made to the homepageapp.get('/', function(req, res) {
  res.send('hello world');
});



作者:miku設定
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1795/viewspace-2817342/,如需轉載,請註明出處,否則將追究法律責任。

相關文章