JavaScript >> Javascript 文檔 >  >> Node.js

Express.js 簡介:參數、錯誤處理和其他中間件

注意: 本文是 Express.js 指南的一部分:Express.js 綜合書籍。

Express.js 是最流行和最成熟的 Node.js 框架之一。您可以在 Express.js 簡介 中了解更多信息 webapplog.com 上的系列:

  • Express.js 簡介:使用 Monk 和 MongoDB 的簡單 REST API 應用
  • Node.js MVC:Express.js + Derby Hello World 教程

要了解如何從頭開始創建應用程序,請參閱之前的帖子。

請求處理程序

Express.js 是一個 node.js 框架,它提供了一種組織路由的方法。每個路由都是通過對應用程序對象的方法調用定義的,其中 URL 模式作為第一個參數(也支持正則表達式),例如:

app.get('api/v1/stories/', function(res, req){
  ...
})

或者,對於 POST 方法:

app.post('/api/v1/stories'function(req,res){
  ...
})

不用說也支持 DELETE 和 PUT 方法。
我們傳遞給 get() 的回調 或 post() 方法稱為請求處理程序,因為它們接受請求(req ),處理它們並寫入響應 (res ) 對象。例如:

app.get('/about', function(req,res){
  res.send('About Us: ...');
});

我們可以有多個請求處理程序,因此名稱 middleware .他們接受第三個參數 next 調用 which (next() ) 將執行流程切換到下一個處理程序:

app.get('/api/v1/stories/:id', function(req,res, next) {
  //do authorization
  //if not authorized or there is an error 
  // return next(error);
  //if authorized and no errors
  return next();
}), function(req,res, next) {
  //extract id and fetch the object from the database
  //assuming no errors, save story in the request object
  req.story = story;
  return next();
}), function(req,res) {
  //output the result of the database search
  res.send(res.story);
});

URL模式中故事的ID是一個查詢字符串參數,我們需要在數據庫中找到匹配的項目。

參數中間件

參數是在請求的 URL 的查詢字符串中傳遞的值。如果我們沒有 Express.js 或類似的庫,而只能使用核心 Node.js 模塊,我們就必須通過一些 require('querystring').parse(url) 從 HTTP.request 對像中提取參數 或 require('url').parse(url, true) 功能詭計。

感謝 Connect 框架和 VisionMedia 的人員,Express.js 已經以中間件的形式支持參數、錯誤處理和許多其他重要功能。這就是我們如何在我們的應用程序中插入參數中間件:

app.param('id', function(req,res, next, id){
  //do something with id
  //store id or other info in req object
  //call next when done
  next();
});

app.get('/api/v1/stories/:id',function(req,res){
  //param middleware will be execute before and
  //we expect req object already have needed info
  //output something
  res.send(data);
});

例如:

app.param('id', function(req,res, next, id){
  req.db.get('stories').findOne({_id:id}, function (e, story){
    if (e) return next(e);
    if (!story) return next(new Error('Nothing is found'));
    req.story = story;
    next();
  });
});

app.get('/api/v1/stories/:id',function(req,res){
  res.send(req.story);
});

或者我們可以使用多個請求處理程序,但概念保持不變:我們可以期望有 req.story 對像或在執行此代碼之前拋出的錯誤,因此我們抽象了獲取參數及其各自對象的通用代碼/邏輯:

app.get('/api/v1/stories/:id', function(req,res, next) {
  //do authorization
  }),
  //we have an object in req.story so no work is needed here
  function(req,res) {
  //output the result of the database search
  res.send(story);
});

授權和輸入衛生也是駐留在中間件中的不錯選擇。

函數param() 特別酷,因為我們可以組合不同的鍵,例如:

app.get('/api/v1/stories/:storyId/elements/:elementId',function(req,res){
  res.send(req.element);
});

錯誤處理

錯誤處理通常在整個應用程序中使用,因此最好將其實現為中間件。它有相同的參數加上一個,error

[旁注]

閱讀博客文章很好,但觀看視頻課程更好,因為它們更具吸引力。

許多開發人員抱怨 Node.js 上缺乏負擔得起的高質量視頻材料。觀看 YouTube 視頻會讓人分心,花 500 美元購買 Node 視頻課程很瘋狂!

去看看 Node University,它有關於 Node 的免費視頻課程:node.university。

[旁注結束]

app.use(function(err, req, res, next) {
  //do logging and user-friendly error message display
  res.send(500);
})

其實響應可以是任何東西:

JSON 字符串

app.use(function(err, req, res, next) {
  //do logging and user-friendly error message display
  res.send(500, {status:500, message: 'internal error', type:'internal'});
})

短信

app.use(function(err, req, res, next) {
  //do logging and user-friendly error message display
  res.send(500, 'internal server error');
})

錯誤頁面

app.use(function(err, req, res, next) {
  //do logging and user-friendly error message display
  //assuming that template engine is plugged in
  res.render('500');
})

重定向到錯誤頁面

app.use(function(err, req, res, next) {
  //do logging and user-friendly error message display
  res.redirect('/public/500.html');
})

錯誤 HTTP 響應狀態(401、400、500 等)

app.use(function(err, req, res, next) {
  //do logging and user-friendly error message display
  res.end(500);
})

順便說一句,日誌記錄也應該抽像在一個中間件中!

要從請求處理程序和中間件中觸發錯誤,您只需調用:

next(error);

next(new Error('Something went wrong :-(');

您還可以擁有多個錯誤處理程序,並使用命名函數而不是匿名函數,如 Express.js 錯誤處理指南中所示。

其他中間件

除了提取參數之外,它還可以用於許多事情,例如授權、錯誤處理、會話、輸出等。

res.json() 是其中之一。它方便地將 JavaScript/Node.js 對象輸出為 JSON。例如:

app.get('/api/v1/stories/:id', function(req,res){
  res.json(req.story);
});

相當於(如果 req.story 是一個數組和對象):

app.get('/api/v1/stories/:id', function(req,res){
  res.send(req.story);
});

app.get('api/v1/stories/:id',function(req,res){
  res.set({
    'Content-Type': 'application/json'
  });
  res.send(req.story);
});

抽象

中間件是靈活的。您可以使用匿名或命名函數,但最好的辦法是根據功能將請求處理程序抽像到外部模塊中:

var stories = require.('./routes/stories');
var elements = require.('./routes/elements');
var users = require.('./routes/users');
...
app.get('/stories/,stories.find);
app.get('/stories/:storyId/elements/:elementId', elements.find);
app.put('/users/:userId',users.update);

路線/故事.js:

module.exports.find = function(req,res, next) {
};

路線/元素.js:

module.exports.find = function(req,res,next){
};

路線/users.js:

module.exports.update = function(req,res,next){
};

你可以使用一些函數式編程技巧,像這樣:

function requiredParamHandler(param){
  //do something with a param, e.g., check that it's present in a query string
  return function (req,res, next) {
    //use param, e.g., if token is valid proceed with next();
    next();
  });
}

app.get('/api/v1/stories/:id', requiredParamHandler('token'), story.show);

var story  = {
  show: function (req, res, next) {
    //do some logic, e.g., restrict fields to output
    return res.send();
  }
}   

如您所見,中間件是保持代碼組織的強大概念。最佳實踐是通過將所有邏輯移動到相應的外部模塊/文件中來保持路由器精簡。這樣,重要的服務器配置參數將整齊地放在一個地方,當您需要它們時就在那兒! :-)


Tutorial JavaScript 教程
  1. 將 getElementById 用於 [尚未] 在 DOM 中的元素?

  2. JavaScript 按鍵合併對像數組 |示例代碼

  3. 應用函子如何幫助我們驗證表單

  4. 打字稿:重點是什麼?

  5. DBless 與 Nucleoid 運行時

  6. 每個 JavaScript 開發人員都應該知道的十多個數學函數

  7. 使用 jQuery 查找元素並在其中附加值

  1. Codility Ladder javascript – 不理解將答案從 37% 提高到 100% 的細節

  2. 在 React 中自定義 SVG

  3. P-PL.com 尋求 JS 和 Python 專家

  4. 我的替換函數適用於數組,但不適用於同樣是數組的 HTML 集合。為什麼?

  5. (javascript) 如果你有一個字符串,它是一個以數字結尾的單詞。如何在單詞和數字之間添加空格?

  6. 使用 express 製作 HTML5 Canvas 應用

  7. SVG

  1. 使用帶有反應路由器的佈局組件

  2. 🍝 使用 Next.js (React)、GraphQL、Strapi 和 Stripe 製作 Deliveroo 克隆 - 💵 訂購和結帳(第 6/7 部分)

  3. 10+ 最佳 React Material-UI(MUI) 管理儀表板模板

  4. 散景效果、反應卡、懸停目錄等 |模塊星期一 23