国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Restful API 中的錯誤處理

NotFound / 1256人閱讀

簡介

隨著移動開發和前端開發的崛起,越來越多的 Web 后端應用都傾向于實現 Restful API。
Restful API 是一個簡單易用的前后端分離方案,它只需要對客戶端請求進行處理,然后返回結果即可, 無需考慮頁面渲染,一定程度上減輕了后端開發人員的負擔。
然而,正是由于 Restful API 不需要考慮頁面渲染,導致它不能在頁面上展示錯誤信息。
那就意著當出現錯誤的時候,它只能通過返回一個錯誤的響應,來告訴用戶和開發者相應的錯誤信息,提示他們接下來應該怎么辦。
本文將討論 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
}

觀察這些結構可以發現它們都有一些共同的地方:

都利用了 Http 狀態碼

有些返回了業務錯誤碼

都提供了給用戶看的錯誤提示信息

有些提供了給開發者看的錯誤信息

Http 狀態碼

在 Restful API 中利用 Http 狀態碼來表明錯誤類型再合適不過了,因為 Http 狀態碼定義了很多抽象的錯誤類型。
雖然 Http 狀態碼定義了非常多的錯誤類型,但實際應用中,我們常用的狀態碼并不多,通常都是下面這幾方面:

API 正常工作 (200, 201)

客戶端錯誤 (400, 401, 403, 404)

服務端錯誤 (500, 503)

業務錯誤碼

很多時候,我們根據業務類型來自定義錯誤碼。
這些業務錯誤碼與 Http 狀態碼并不重疊,這時候我們可以返回業務錯誤碼,用來提示用戶/開發者錯誤類型。

給用戶看的錯誤信息

當出現錯誤的時候,我們需要提示用戶如何處理這種情況,通常這種錯誤信息都是必須的。
可以看到上面幾個例子中都有返回給用戶看的錯誤信息。

給開發者看的錯誤信息

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

設計錯誤類型

我們剛才提到過,可以利用 Http 狀態碼來為錯誤類型進行分類。
通常我們所說的分類通常是對客戶端錯誤進行分類, 即 4xx 類型的錯誤。

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

400 Bad Request
由于包含語法錯誤,當前請求無法被服務器理解。除非進行修改,否則客戶端不應該重復提交這個請求。
通常在請求參數不合法或格式錯誤的時候可以返回這個狀態碼。

401 Unauthorized
當前請求需要用戶驗證。
通常在沒有登錄的狀態下訪問一些受保護的 API 時會用到這個狀態碼。

403 Forbidden
服務器已經理解請求,但是拒絕執行它。與401響應不同的是,身份驗證并不能提供任何幫助。
通常在沒有權限操作資源時(如修改/刪除一個不屬于該用戶的資源時)會用到這個狀態碼。

404 Not Found
請求失敗,請求所希望得到的資源未被在服務器上發現。
通常在找不到資源時返回這個狀態碼。

盡管我們可以通過 Http 狀態碼來表示錯誤的類型,
但在實際應用中,如果僅僅使用 Http 狀態碼的話,我們的代碼中就遍布 Http 狀態碼:

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

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

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

上面的實現方式在小項目中還可以接受,當項目變大、需求變多的時候,維護起來就變得很麻煩了。
為了提高錯誤的可讀性和可維護性,我們需要對各種錯誤進行分類。
我個人習慣把錯誤分成以下幾種類型:

格式錯誤 (FORMAT_INVALID)

數據不存在 (DATA_NOT_FOUND)

數據已存在 (DATA_EXISTED)

數據無效 (DATA_INVALID)

登錄錯誤 (LOGIN_REQUIRED)

權限不足 (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)
}

這種形式比上面的寫死狀態碼的方式方便很多,而且維護起來也更加簡單。
但有一個問題,就是不能根據錯誤類型來返回指定的錯誤信息。

自定義錯誤類型

要實現根據錯誤類型來返回指定的錯誤信息,我們可以通過自定義錯誤的方式來實現。
假設我們自定義錯誤的結構如下:

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

我們需要做到如下幾點:

根據錯誤類型來自動設置 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
  }
}

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

// 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")
}

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

捕獲錯誤信息

在 Controller 中拋出自定義錯誤后,我們需要捕獲該錯誤,才能返回給客戶端。
假設我們使用 koa 2 作為 web 框架來開發 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())

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

參考資料

https://zh.wikipedia.org/zh-hans/HTTP%E7%8A%B6%E6%80%81%E7%A0%81
https://www.loggly.com/blog/n...
http://blog.restcase.com/rest...
https://apigee.com/about/blg/...
http://stackoverflow.com/ques...
http://goldbergyoni.com/check...
http://blogs.mulesoft.com/dev...
https://developers.facebook.c...
https://developers.google.com...
https://developer.github.com/...
https://dev.twitter.com/overv...
https://www.twilio.com/docs/a...

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/75712.html

相關文章

  • 7點關于RESTful規范的API接口設計的想法

    摘要:返回值結構在完成了上面的部署之后,接下來我們來看看返回結果應該怎么樣來確定。因為返回值中,我們常常要對數據進行區分分組,或者按照從屬關系打包,所以,我們再返回時,最好有包裹的思想,把數據存放在不同的包裹中進行返回。 在項目中,需要為APP撰寫API。剛開始接觸的時候,并沒有考慮太多,就想提供URL,APP端通過該URL進行查詢、創建、更新等操作即可。但再對相關規范進行了解后,才發現,A...

    Jason 評論0 收藏0
  • 使用swagger 生成 Flask RESTful API

    摘要:指定篩選條件選擇合適的狀態碼應答中,需要帶一個很重要的字段。返回結果針對不同操作,服務器向用戶返回的結果應該符合以下規范。如果狀態碼是,就應該向用戶返回出錯信息。 什么是 RESTful 什么是REST REST(英文:Representational State Transfer,又稱具象狀態傳輸)是Roy Thomas Fielding博士于2000年在他的博士論文 中提出來的一種...

    printempw 評論0 收藏0
  • Flask 擴展系列之 Flask-RESTful

    摘要:勵以最少的安裝方式進行最佳實踐。上面的例子接收了一個對象并準備將其序列化。裝飾器會通過進行轉換。從對象中提取的唯一字段是。是一個特殊的字段,它接受端點名稱并為響應中的端點生成一個。可以查看項查看完整列表。 大綱 簡介 安裝 快速入門 一個最小的 api 例子 資源豐富的路由 端點 參數解析 數據格式化 完整 TODO 應用例子 簡介 Flask-RESTful是一個Flas...

    阿羅 評論0 收藏0
  • SpringBoot RESTful 應用中的異常處理小結

    摘要:和的區別方法注解作用于級別注解為一個定義一個異常處理器類注解作用于整個工程注解定義了一個全局的異常處理器需要注意的是的優先級比高即拋出的異常如果既可以讓標注的方法處理又可以讓標注的類中的方法處理則優先讓標注的方法處理處理中的異常為了方便地展 @ControllerAdvice 和 @ExceptionHandler 的區別 ExceptionHandler, 方法注解, 作用于 Co...

    jackzou 評論0 收藏0
  • 人人都是 API 設計師:我對 RESTful API、GraphQL、RPC API 的思考

    摘要:通常情況下,偽都是基于第一層次與第二層次設計的。為了解決這個版本不兼容問題,在設計的一種實用的做法是使用版本號。例如,建議第三位版本號通常表示兼容升級,只有不兼容時才需要變更服務版本。 原文地址:梁桂釗的博客 博客地址:blog.720ui.com 歡迎關注公眾號:「服務端思維」。一群同頻者,一起成長,一起精進,打破認知的局限性。 有一段時間沒怎么寫文章了,今天提筆寫一篇自己對 API 設...

    ormsf 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<