最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Restful API中的錯誤處理方法

 更新時間:2019年08月01日 11:22:07   作者:alterem  
這篇文章主要給大家介紹了關(guān)于Restful API中錯誤處理方法的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧

簡介

隨著移動開發(fā)和前端開發(fā)的崛起,越來越多的 Web 后端應用都傾向于實現(xiàn) Restful API。

Restful API 是一個簡單易用的前后端分離方案,它只需要對客戶端請求進行處理,然后返回結(jié)果即可, 無需考慮頁面渲染,一定程度上減輕了后端開發(fā)人員的負擔。

然而,正是由于 Restful API 不需要考慮頁面渲染,導致它不能在頁面上展示錯誤信息。

那就意著當出現(xiàn)錯誤的時候,它只能通過返回一個錯誤的響應,來告訴用戶和開發(fā)者相應的錯誤信息,提示他們接下來應該怎么辦。

本文將討論 Restful API 中的錯誤處理方案。

設計錯誤信息

當 Restful API 需要拋出錯誤的時候,我們要考慮的是:這個錯誤應該包含哪些信息。

我們先看看 Github, Google, Facebook, Twitter, Twilio 的錯誤信息是怎樣的。

Github (use http status)

{
 "message": "Validation Failed",
 "errors": [
 {
  "resource": "Issue",
  "field": "title",
  "code": "missing_field"
 }
 ]
}

Google (use http status)

{
 "error": {
 "errors": [
  {
  "domain": "global",
  "reason": "insufficientFilePermissions",
  "message": "The user does not have sufficient permissions for file {fileId}."
  }
 ],
 "code": 403,
 "message": "The user does not have sufficient permissions for file {fileId}."
 }
}

Facebook (use http status)

{
 "error": {
 "message": "Message describing the error", 
 "type": "OAuthException",
 "code": 190,
 "error_subcode": 460,
 "error_user_title": "A title",
 "error_user_msg": "A message",
 "fbtrace_id": "EJplcsCHuLu"
 }
}

Twitter (use http status)

{
 "errors": [
 {
  "message": "Sorry, that page does not exist",
  "code": 34
 }
 ]
}

Twilio (use http status)

{
 "code": 21211,
 "message": "The 'To' number 5551234567 is not a valid phone number.",
 "more_info": "https://www.twilio.com/docs/errors/21211",
 "status": 400
}

觀察這些結(jié)構(gòu)可以發(fā)現(xiàn)它們都有一些共同的地方:

  • 都利用了 Http 狀態(tài)碼
  • 有些返回了業(yè)務錯誤碼
  • 都提供了給用戶看的錯誤提示信息
  • 有些提供了給開發(fā)者看的錯誤信息

Http 狀態(tài)碼

在 Restful API 中利用 Http 狀態(tài)碼來表明錯誤類型再合適不過了,因為 Http 狀態(tài)碼定義了很多抽象的錯誤類型。

雖然 Http 狀態(tài)碼定義了非常多的錯誤類型,但實際應用中,我們常用的狀態(tài)碼并不多,通常都是下面這幾方面:

  • API 正常工作 (200, 201)
  • 客戶端錯誤 (400, 401, 403, 404)
  • 服務端錯誤 (500, 503)

業(yè)務錯誤碼

很多時候,我們根據(jù)業(yè)務類型來自定義錯誤碼。

這些業(yè)務錯誤碼與 Http 狀態(tài)碼并不重疊,這時候我們可以返回業(yè)務錯誤碼,用來提示用戶/開發(fā)者錯誤類型。

給用戶看的錯誤信息

當出現(xiàn)錯誤的時候,我們需要提示用戶如何處理這種情況,通常這種錯誤信息都是必須的。

可以看到上面幾個例子中都有返回給用戶看的錯誤信息。

給開發(fā)者看的錯誤信息

若我們的 API 需要開放給第三方開發(fā)者,那么我們就需要考慮返回一些給開發(fā)者看的錯誤信息。

設計錯誤類型

我們剛才提到過,可以利用 Http 狀態(tài)碼來為錯誤類型進行分類。

通常我們所說的分類通常是對客戶端錯誤進行分類, 即 4xx 類型的錯誤。

而這些錯誤類型中,我們最常用的是:

  • 400 Bad Request
    由于包含語法錯誤,當前請求無法被服務器理解。除非進行修改,否則客戶端不應該重復提交這個請求。
    通常在請求參數(shù)不合法或格式錯誤的時候可以返回這個狀態(tài)碼。
  • 401 Unauthorized
    當前請求需要用戶驗證。
    通常在沒有登錄的狀態(tài)下訪問一些受保護的 API 時會用到這個狀態(tài)碼。
  • 403 Forbidden
    服務器已經(jīng)理解請求,但是拒絕執(zhí)行它。與401響應不同的是,身份驗證并不能提供任何幫助。
    通常在沒有權(quán)限操作資源時(如修改/刪除一個不屬于該用戶的資源時)會用到這個狀態(tài)碼。
  • 404 Not Found
    請求失敗,請求所希望得到的資源未被在服務器上發(fā)現(xiàn)。
    通常在找不到資源時返回這個狀態(tài)碼。

盡管我們可以通過 Http 狀態(tài)碼來表示錯誤的類型,

但在實際應用中,如果僅僅使用 Http 狀態(tài)碼的話,我們的代碼中就遍布 Http 狀態(tài)碼:

// Node.js
if (!res.body.title) {
 res.statusCode = 400
}

if (!user) {
 res.statusCode = 401
}

if (!post) {
 res.statusCode = 404
}

上面的實現(xiàn)方式在小項目中還可以接受,當項目變大、需求變多的時候,維護起來就變得很麻煩了。

為了提高錯誤的可讀性和可維護性,我們需要對各種錯誤進行分類。

我個人習慣把錯誤分成以下幾種類型:

  • 格式錯誤 (FORMAT_INVALID)
  • 數(shù)據(jù)不存在 (DATA_NOT_FOUND)
  • 數(shù)據(jù)已存在 (DATA_EXISTED)
  • 數(shù)據(jù)無效 (DATA_INVALID)
  • 登錄錯誤 (LOGIN_REQUIRED)
  • 權(quán)限不足 (PERMISSION_DENIED)

錯誤分類之后,我們拋錯誤的時候就變得更加直觀了:

if (!res.body.title) {
 throw new Error(ERROR.FORMAT_INVALID)
}

if (!user) {
 throw new Error(ERROR.LOGIN_REQUIRED)
}

if (!post) {
 throw new Error(ERROR.DATA_NOT_FOUND)
}

if (post.creator.id !== user.id) {
 throw new Error(ERROR.PERMISSION_DENIED)
}

這種形式比上面的寫死狀態(tài)碼的方式方便很多,而且維護起來也更加簡單。

但有一個問題,就是不能根據(jù)錯誤類型來返回指定的錯誤信息。

自定義錯誤類型

要實現(xiàn)根據(jù)錯誤類型來返回指定的錯誤信息,我們可以通過自定義錯誤的方式來實現(xiàn)。

假設我們自定義錯誤的結(jié)構(gòu)如下:

{
 "type": "",
 "code": 0,
 "message": "",
 "detail": ""
}

我們需要做到如下幾點:

  • 根據(jù)錯誤類型來自動設置type, code, message
  • detail 為可選項,用來描述該錯誤的具體原因
const ERROR = {
 FORMAT_INVALID: 'FORMAT_INVALID',
 DATA_NOT_FOUND: 'DATA_NOT_FOUND',
 DATA_EXISTED: 'DATA_EXISTED',
 DATA_INVALID: 'DATA_INVALID',
 LOGIN_REQUIRED: 'LOGIN_REQUIRED',
 PERMISSION_DENIED: 'PERMISSION_DENIED'
}

const ERROR_MAP = {
 FORMAT_INVALID: {
  code: 1,
  message: 'The request format is invalid'
 },
 DATA_NOT_FOUND: {
  code: 2,
  message: 'The data is not found in database'
 },
 DATA_EXISTED: {
  code: 3,
  message: 'The data has exist in database'
 },
 DATA_INVALID: {
  code: 4,
  message: 'The data is invalid'
 },
 LOGIN_REQUIRED: {
  code 5,
  message: 'Please login first'
 },
 PERMISSION_DENIED: {
  code: 6,
  message: 'You have no permission to operate'
 }
}

class CError extends Error {
 constructor(type, detail) {
  super()
  Error.captureStackTrace(this, this.constructor)

  let error = ERROR_MAP[type]
  if (!error) {
   error = {
    code: 999,
    message: 'Unknow error type'
   }
  }

  this.name = 'CError'
  this.type = error.code !== 999 ? type : 'UNDEFINED'
  this.code = error.code
  this.message = error.message
  this.detail = detail
 }
}

自定義好錯誤之后,我們調(diào)用起來就更加簡單了:

// in controller
if (!user) {
 throw new CError(ERROR.LOGIN_REQUIRED, 'You should login first')
}

if (!req.body.title) {
 throw new CError(ERROR.FORMAT_INVALID, 'Title is required')
}

if (!post) {
 throw new CError(ERROR.DATA_NOT_FOUND, 'The post you required is not found')
}

最后,還剩下一個問題,根據(jù)錯誤類型來設置狀態(tài)碼,然后返回錯誤信息給客戶端。

捕獲錯誤信息

在 Controller 中拋出自定義錯誤后,我們需要捕獲該錯誤,才能返回給客戶端。

假設我們使用 koa 2 作為 web 框架來開發(fā) restful api,那么我們要做的是添加錯誤處理的中間件:

module.exports = async function errorHandler (ctx, next) {
 try {
  await next()
 } catch (err) {

  let status

  switch (err.type) {
   case ERROR.FORMAT_INVALID:
   case ERROR.DATA_EXISTED:
   case ERROR.DATA_INVALID:
    status = 400
    break
   case ERROR.LOGIN_REQUIRED:
    status = 401
   case ERROR.PERMISSION_DENIED:
    status = 403
   case ERROR.DATA_NOT_FOUND:
    status = 404
    break
   default:
    status = 500
  }

  ctx.status = status
  ctx.body = err
 }
}

// in app.js
app.use(errorHandler)
app.use(router.routes())

通過這種方式,我們就能優(yōu)雅地處理 Restful API 中的錯誤信息了。

參考資料

  • https://zh.wikipedia.org/zh-hans/HTTP%E7%8A%B6%E6%80%81%E7%A0%81
  • https://www.loggly.com/blog/node-js-error-handling/
  • http://blog.restcase.com/rest-api-error-codes-101/
  • https://apigee.com/about/blg/technology/restful-api-design-what-about-errors
  • http://stackoverflow.com/questions/942951/rest-api-error-return-good-practices
  • http://goldbergyoni.com/checklist-best-practices-of-node-js-error-handling/
  • http://blogs.mulesoft.com/dev/api-dev/api-best-practices-response-handling/
  • https://developers.facebook.com/docs/graph-api/using-graph-api/#errors
  • https://developers.google.com/drive/v3/web/handle-errors
  • https://developer.github.com/v3/#client-errors
  • https://dev.twitter.com/overview/api/response-codes
  • https://www.twilio.com/docs/api/errors

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持。

相關(guān)文章

  • Java中的Semaphore信號量簡單使用代碼實例

    Java中的Semaphore信號量簡單使用代碼實例

    這篇文章主要介紹了Java中的Semaphore信號量簡單使用代碼實例,Semaphore是用來保護一個或者多個共享資源的訪問,Semaphore內(nèi)部維護了一個計數(shù)器,其值為可以訪問的共享資源的個數(shù),一個線程要訪問共享資源,需要的朋友可以參考下
    2023-12-12
  • JavaMap兩種遍歷方式keySet與entrySet詳解

    JavaMap兩種遍歷方式keySet與entrySet詳解

    這篇文章主要介紹了JavaMap兩種遍歷方式keySet與entrySet,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧
    2023-03-03
  • 高內(nèi)聚低耦合原則_動力節(jié)點Java學院整理

    高內(nèi)聚低耦合原則_動力節(jié)點Java學院整理

    耦合度就是某模塊(類)與其它模塊(類)之間的關(guān)聯(lián)、感知和依賴的程度,是衡量代碼獨立性的一個指標,也是軟件工程設計及編碼質(zhì)量評價的一個標準
    2017-08-08
  • Java并發(fā)編程之Volatile變量詳解分析

    Java并發(fā)編程之Volatile變量詳解分析

    Volatile關(guān)鍵字是Java提供的一種輕量級的同步機制,本篇文章深入淺出的講講Java并發(fā)編程的Volatile,通讀本篇對大家的學習或工作具有一定的價值,需要的朋友可以參考下
    2021-10-10
  • Spring純注解開發(fā)模式讓開發(fā)簡化更簡化

    Spring純注解開發(fā)模式讓開發(fā)簡化更簡化

    Spring3.0引入了純注解開發(fā)的模式,框架的誕生是為了簡化開發(fā),那注解開發(fā)就是簡化再簡化。Spring的特性在整合MyBatis方面體現(xiàn)的淋漓盡致哦
    2022-08-08
  • RabbitMQ實現(xiàn)Work Queue工作隊列的示例詳解

    RabbitMQ實現(xiàn)Work Queue工作隊列的示例詳解

    工作隊列(又稱任務隊列)的主要思想是避免立即執(zhí)行資源密集型任務,而不得不等待它完成。本篇文章將記錄和分享RabbitMQ工作隊列相關(guān)的知識點,希望對大家有所幫助
    2023-01-01
  • SpringBoot配置文件密碼加密的三種方案

    SpringBoot配置文件密碼加密的三種方案

    這篇文章主要介紹了SpringBoot配置文件密碼加密的三種方案,文中通過代碼示例給大家介紹的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下
    2024-04-04
  • SpringBoot集成Jasypt敏感信息加密的操作方法

    SpringBoot集成Jasypt敏感信息加密的操作方法

    這篇文章主要介紹了SpringBoot集成Jasypt加密敏感信息,包括敏感信息加密的作用,項目集成Jasypt方式詳解,本文給大家介紹的非常詳細,需要的朋友可以參考下
    2022-05-05
  • springboot關(guān)閉druid監(jiān)控 druid2改配置文件無效的解決

    springboot關(guān)閉druid監(jiān)控 druid2改配置文件無效的解決

    這篇文章主要介紹了springboot關(guān)閉druid監(jiān)控 druid2改配置文件無效的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • 出現(xiàn)SLF4J:?Failed?to?load?class?“org.slf4j.impl.StaticLoggerBinder“.的解決方法

    出現(xiàn)SLF4J:?Failed?to?load?class?“org.slf4j.impl.StaticLog

    本文主要介紹了出現(xiàn)SLF4J:?Failed?to?load?class?“org.slf4j.impl.StaticLoggerBinder“.的解決方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-07-07

最新評論

江津市| 达孜县| 马龙县| 麻城市| 凤凰县| 秭归县| 松阳县| 邯郸市| 普宁市| 巴马| 桂林市| 鄂托克前旗| 郑州市| 鸡泽县| 景德镇市| 同江市| 晋宁县| 密山市| 酒泉市| 阜新市| 南通市| 兴化市| 屏南县| 嘉祥县| 苏州市| 荆州市| 龙泉市| 宁国市| 海林市| 论坛| 丹巴县| 双峰县| 大冶市| 临海市| 石柱| 杂多县| 潢川县| 宜黄县| 图木舒克市| 巢湖市| 修文县|