1. 程式人生 > >Node.js之Express4.x

Node.js之Express4.x

一、安裝及專案建立

1.官網下載安裝node.js(不提)
2.express4.x安裝

$ npm install -g express-generator  
注意:4.x把命令列工具分離出來了,express-generator必須先全域性安裝,
如果需要安裝指定版本: npm install -g express-generator@3.5.0

$ npm install express --save   
注意:express 沒必要全域性安裝,但最好 安裝的同時,進行儲存,即 加上 --save.  此處 express 最好和 上面的 express-generator
版本一致 $ npm install *** --save 注意:其他模組的安裝類似 express 模組,也可不全域性安裝,但最好 安裝的同時,進行儲存,即 加上 --save. 解除安裝模組使用: npm uninstall express

3.建立NodeJS專案

$ express --view=jade extest
引數:jade :是建立的專案模板  # 專案模板共有多種(常見的有): ejs,hbs,pug,jade,haml,....等,可使用$ express -h進行檢視
     mytest:是專案名稱

這裡寫圖片描述

按照指示進入目錄進行安裝依賴:

$ cd extest && npm install   # 該句實際包含兩條命令:進入專案 和 安裝依賴包

啟動:

npm start
注意:express 4.x 無法以 node app.js 為啟動方式

客戶端輸入:localhost:3000,如果展示下面的形式,則表示安裝成功。
這裡寫圖片描述

二、專案介紹

1.目錄結構
生成的目錄結構如下圖所示:
這裡寫圖片描述
bin, 存放啟動專案的指令碼檔案
node_modules, 存放所有的專案依賴庫
public,靜態檔案(css,js,img)
routes,路由檔案(MVC中的C,controller)
views,頁面檔案(相關模板)
package.json,專案依賴配置及開發者資訊
app.js,應用核心配置檔案
2.package.json配置檔案


這裡寫圖片描述
裡面展示我們依賴配置的版本號,其中scripts屬性是用於定義操作命令的,可以非常方便的增加啟動命令,比如預設的start,用npm start代表執行node ./bin/www命令。
3.app.js核心開發檔案
node開發的核心程式碼在這兒編寫,中間樞紐。

//載入依賴庫
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var logger = require('morgan');
//載入路由控制
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
///建立專案例項
var app = express();

// 定義jade模板引擎和模板檔案位置
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// 定義日誌和輸出級別
app.use(logger('dev'));
//定義資料解析器
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
//定義cookie解析器
app.use(cookieParser());
//定義靜態檔案目錄
app.use(express.static(path.join(__dirname, 'public')));
// 匹配路徑和路由
app.use('/', indexRouter);
app.use('/users', usersRouter);

// 404錯誤處理
app.use(function(req, res, next) {
  next(createError(404));
});

// 開發環境,500錯誤處理
app.use(function(err, req, res, next) {
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};
  res.status(err.status || 500);
  res.render('error');
});

// 生產環境,500錯誤處理
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});


//輸出模型
module.exports = app;

4.bin/www專案啟動檔案
www檔案是一個node的指令碼,用於分離配置和啟動程式

#!/usr/bin/env node

/**
 * 依賴載入
 */

var app = require('../app');
var debug = require('debug')('extest:server');
var http = require('http');

/**
 * 定義啟動埠
 */

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
 * 建立HTTP服務例項
 */

var server = http.createServer(app);

/**
 * 啟動網路服務監聽埠
 */

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
 * 前端標準化函式
 */

function normalizePort(val) {
  var port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

/**
 * HTTP異常事件處理函式
 */

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;
  }
}

/**
 * 事件繫結函式
 */

function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
}

5.路由
路由決定了由誰(指定指令碼)去響應客戶端請求,其實就是後端介面。
路由的幾種寫法:

var express = require('express');
var router = express.Router();

(1)router.all(path, [callback, ...] callback)
    router.all('*', [callback, ...] callback) //匹配所有的HTTP請求
    router.all('/api/*', [callback, ...] callback) //匹配所有以api開頭的路由
(2)router.METHOD((path, [callback, ...] callback)
    router.get(path, [callback, ...] callback) //方法不同,其餘沒什麼區別
    router.put(path, [callback, ...] callback)
    router.post(path, [callback, ...] callback)
(3)router.param(name, callback) //這個方法必須接受兩個引數並且返回一箇中間件。這個回撥的第一個引數就是需要捕獲的url的引數名,第二個引數可以是任一的JavaScript物件,其可能在實現返回一箇中間件時被使用。這個回撥方法返回的中介軟體決定了當URL中包含這個引數時所採取的行為。
//注意:在定義param的路由上,param回撥都是第一個被呼叫的,它們在一個請求-響應迴圈中都會被呼叫一次並且只有一次,即使多個路由都匹配。
(4)router.route(path)//返回一個單例模式的路由的例項,之後你可以在其上施加各種HTTP動作的中介軟體。一個路由,多次不同調用。
    router.roue(path)
          .all(callback)
          .get(callback)
          .put(callback)
          .post(callback)
          .delete(callback)
(5)router.use([path], [function, ...] function) //給可選的path引數按照指定的路徑掛載給定的中介軟體方法,未指定path引數,預設值為/。中間們是按序被呼叫的,所以順序決定了中介軟體的優先順序。
    router.use(callback1)//按順序從上往下執行
    router.use(callback2)
    router.use(callback3)
module.exports = router;

6、request 和 response 物件
Request 物件 - request 物件表示 HTTP 請求,包含了請求查詢字串,引數,內容,HTTP 頭部等屬性。常見屬性有:

req.app:當callback為外部檔案時,用req.app訪問express的例項
req.baseUrl:獲取路由當前安裝的URL路徑
req.body / req.cookies:獲得「請求主體」/ Cookies。解析引數的時候需要用到body_parser和cookie_parser
req.fresh / req.stale:判斷請求是否還「新鮮」
req.hostname / req.ip:獲取主機名和IP地址
req.originalUrl:獲取原始請求URL
req.params:獲取路由的parameters
req.path:獲取請求路徑
req.protocol:獲取協議型別
req.query:獲取URL的查詢引數串
req.route:獲取當前匹配的路由
req.subdomains:獲取子域名
req.accepts():檢查可接受的請求的文件型別
req.acceptsCharsets / req.acceptsEncodings / req.acceptsLanguages:返回指定字符集的第一個可接受字元編碼
req.get():獲取指定的HTTP請求頭
req.is():判斷請求頭Content-Type的MIME型別

Response 物件 - response 物件表示 HTTP 響應,即在接收到請求時向客戶端傳送的 HTTP 響應資料。常見屬性有:

res.app:同req.app一樣
res.append():追加指定HTTP頭
res.set()在res.append()後將重置之前設定的頭
res.cookie(name,value [,option]):設定Cookie
opition: domain / expires / httpOnly / maxAge / path / secure / signed
res.clearCookie():清除Cookie
res.download():傳送指定路徑的檔案
res.get():返回指定的HTTP頭
res.json():傳送JSON響應
res.jsonp():傳送JSONP響應
res.location():只設置響應的Location HTTP頭,不設定狀態碼或者close response
res.redirect():設定響應的Location HTTP頭,並且設定狀態碼302
res.render(view,[locals],callback):渲染一個view,同時向callback傳遞渲染後的字串,如果在渲染過程中有錯誤發生next(err)將會被自動呼叫。callback將會被傳入一個可能發生的錯誤以及渲染後的頁面,這樣就不會自動輸出了。
res.send():傳送HTTP響應
res.sendFile(path [,options] [,fn]):傳送指定路徑的檔案 -會自動根據檔案extension設定Content-Type
res.set():設定HTTP頭,傳入object可以一次設定多個頭
res.status():設定HTTP狀態碼
res.type():設定Content-Type的MIME型別