1. 程式人生 > >Spring Boot提供RESTful介面時的錯誤處理實踐

Spring Boot提供RESTful介面時的錯誤處理實踐

本文首發於個人網站:http://www.javaadu.online/,如需轉載,請註明出處

使用Spring Boot開發微服務的過程中,我們會使用別人提供的介面,也會設計介面給別人使用,這時候微服務應用之間的協作就需要有一定的規範。

  • 基於rpc協議,我們一般有兩種思路:(1)提供服務的應用統一將異常包起來,然後用錯誤碼互動;(2)提供服務的應用將執行時異常丟擲,丟擲自定義的業務異常,服務的呼叫者通過異常catch來處理異常情況。

  • 基於HTTP協議,那麼最流行的就是RESTful協議,服務提供方會自己處理所有異常,並且返回的結果中會跟HTTP的狀態碼相結合,這篇文章我們就用一個例子來說明RESTful介面的錯誤處理如何做。

首先我們需要新建一個簡單的Controller,程式碼如下:

@RestController
class GreetingController {

    @RequestMapping("/greet")
    String sayHello(@RequestParam("name") String name) {
        if (name == null || name.isEmpty()) {
            throw new IllegalArgumentException("The 'name' parameter must not be null or empty");
        }
        return String.format("Hello %s!", name);
    }
}

通過http請求客戶端——httpie傳送HTTP請求,這個工具比curl的好處是:返回值資訊有語法高亮、對返回的JSON字串自動格式化。啟動伺服器,使用命令http http://127.0.0.1:8080/greet?name=duqi發起請求,結果如下:

HTTP/1.1 200 OK
Content-Length: 11
Content-Type: text/plain;charset=UTF-8
Date: Sat, 05 Dec 2015 05:45:03 GMT
Server: Apache-Coyote/1.1
X-Application-Context: application

現在我們製造一個錯誤的請求,@RequestParam是獲取URL中的引數,如果這個引數不提供則會出錯。因此,我們傳送一個命令http http://127.0.0.1:8080

,看結果如何。

HTTP/1.1 400 Bad Request
Connection: close
Content-Type: application/json;charset=UTF-8
Date: Sat, 05 Dec 2015 05:54:06 GMT
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
X-Application-Context: application

{
    "error": "Bad Request",
    "exception": "org.springframework.web.bind.MissingServletRequestParameterException",
    "message": "Required String parameter 'name' is not present",
    "path": "/greet",
    "status": 400,
    "timestamp": 1449294846060
}

可以看到,由於沒有提供name引數,伺服器返回的狀態碼是400:錯誤的請求。在響應體中的內容依次如下:

  • error : 錯誤資訊;
  • exception:異常的型別,MissingServletRequestParameterExeption,見名知意,說明是缺少了某個請求引數;
  • message:對異常的說明
  • path:顯示請求的URL路徑;
  • status:表示返回的錯誤碼
  • timestamp:錯誤發生的時間戳,呼叫System.currentMills()

如果我們給定name引數,卻不給它賦值,又會如何?傳送命令http http:127.0.0.1:8080/greet?name,則伺服器的返回值如下:

HTTP/1.1 500 Internal Server Error
Connection: close
Content-Type: application/json;charset=UTF-8
Date: Sat, 05 Dec 2015 06:01:24 GMT
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
X-Application-Context: application

{
    "error": "Internal Server Error",
    "exception": "java.lang.IllegalArgumentException",
    "message": "The 'name' parameter must not be null or empty",
    "path": "/greet",
    "status": 500,
    "timestamp": 1449295284160
}

對比上面,可以看出,這次返回的錯誤碼是500,表示伺服器內部錯誤;返回的異常型別是java.lang.IllegalArgumentException,表示引數不合法。伺服器內部錯誤表示伺服器丟擲了異常缺沒有處理,我們更願意API返回400,告訴呼叫者自己哪裡做錯了。如何實現呢?利用@ExceptionHandler註解即可。

在GreetingController控制器中加入如下處理函式,用於捕獲這個控制器的異常。

@ExceptionHandler
void handleIllegalArgumentException(IllegalArgumentException e, 
                        HttpServletResponse response) throws IOException {    
      response.sendError(HttpStatus.BAD_REQUEST.value());
}

再次傳送命令http http:127.0.0.1:8080/greet?name,則返回下面的結果:

HTTP/1.1 400 Bad Request
Connection: close
Content-Type: application/json;charset=UTF-8
Date: Sat, 05 Dec 2015 06:08:50 GMT
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
X-Application-Context: application

{
    "error": "Bad Request",
    "exception": "java.lang.IllegalArgumentException",
    "message": "The 'name' parameter must not be null or empty",
    "path": "/greet",
    "status": 400,
    "timestamp": 1449295729978
}

說明我們在伺服器端捕獲了IllegalArgumentException這個異常,並設定response的返回碼為400。如果你想對多個異常都進行一樣的處理,則上述異常處理程式碼可以修改為下面這樣(給@ExceptionHandler傳入引數):

@ExceptionHandler({IllegalArgumentException.class, NullPointerException.class})
void handleIllegalArgumentException(HttpServletResponse response) throws IOException {
    response.sendError(HttpStatus.BAD_REQUEST.value());
}

現在這個異常處理程式碼是加在當前的這個控制器中,因此它只處理屬於這個控制器的響應,如果我們新建一個類,並用註解@ControllerAdvice修飾,並在這個類中定義上述的異常處理程式碼,則它會負責處理所有的請求。

Spring Boot 1.2.0以後,還支援在response修改對應的message,只要將對應的message資訊傳入sendError函式即可,例如:

@ExceptionHandler({IllegalArgumentException.class, NullPointerException.class})
void handleIllegalArgumentException(HttpServletResponse response) throws IOException {
    response.sendError(HttpStatus.BAD_REQUEST.value(), 
         "Please try again and with a non empty string as 'name'");
}

再次執行同樣的命令,會收到下列反饋:

HTTP/1.1 400 Bad Request
Connection: close
Content-Type: application/json;charset=UTF-8
Date: Sat, 05 Dec 2015 06:21:05 GMT
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
X-Application-Context: application

{
    "error": "Bad Request",
    "exception": "java.lang.IllegalArgumentException",
    "message": "Please try again and with a non empty string as 'name'",
    "path": "/greet",
    "status": 400,
    "timestamp": 1449296465060
}

如果希望驗證請求的引數,可以使用JSR-303 Bean Validation API,並參考Spring Validation。在spring.io上還有一個驗證表單輸入的例子Validating Form Input。

參考資料

  1. 模擬GET/POST請求的工具
  2. Spring Boot Error Response

Spring Boot 1.x系列

  1. Spring Boot的自動配置、Command-line-Runner
  2. 瞭解Spring Boot的自動配置
  3. Spring Boot的@PropertySource註解在整合Redis中的使用
  4. Spring Boot專案中如何定製HTTP訊息轉換器
  5. Spring Boot整合Mongodb提供Restful介面
  6. Spring中bean的scope
  7. Spring Boot專案中使用事件派發器模式

本號專注於後端技術、JVM問題排查和優化、Java面試題、個人成長和自我管理等主題,為讀者提供一線開發者的工作和成長經驗,期待你能在這裡有所收穫。

相關推薦

Spring Boot提供RESTful介面錯誤處理實踐

本文首發於個人網站:http://www.javaadu.online/,如需轉載,請註明出處 使用Spring Boot開發微服務的過程中,我們會使用別人提供的介面,也會設計介面給別人使用,這時候微服務應用之間的協作就需要有一定的規範。 基於rpc協議,我們一般有兩種思路:(1)提供服務的應用統一將異

通過spring boot提供restful api

set err erro init exce cati article pub path 1 將返回設置為produces = "application/json" 返回給客戶端json格式的response。 2 對各種異常的處理 各種異常如何返回給客戶端? 各種異常通過

springboot全域性異常處理(包含404錯誤處理) 一:解決spring boot中rest介面404,500等錯誤返回統一的json格式(備用地址) 二:SpringBoot入門——區域性與全域性的異常處理(備用地址)

個人整理參考文件: 一:解決spring boot中rest介面404,500等錯誤返回統一的json格式(備用地址) 二:SpringBoot入門——區域性與全域性的異常處理(備用地址) 三:SpringBoot全域性異常處理(備用地址) 四:sprin

解決spring boot中rest介面404,500等錯誤返回統一的json格式

在開發rest介面時,我們往往會定義統一的返回格式,列如: { "status": true, "code": 200, "message": null, "data": [ { "id": "101", "name": "jack" },

spring boot 下 500 404 403錯誤頁面處理

1.場景說明 Spring Boot 下http 500 404 403錯誤頁面處理。同時文章是在《SpringBoot介面服務處理Whitelabel Error Page》基礎上新增內容,更加詳細的說明請參考這篇文章。本文直說明差異部分。 2

spring boot 1.5.4 統一異常處理(九)

springboot springboot1.5.4 springboot整合springdatajpa springboot集成jdbctemplate springboot異常處理 上一篇:springboot 1.5.4 配置文件詳解(八) 1 Spring Boot統一異

spring boot框架學習9-spring boot的web開發(5)-錯誤解決及跳轉頁面

凱哥spring boot spring boot框架 本章節主要內容:通過前面的學習,我們了解並快速完成了spring boot第一個應用。spring boot企業級框架,那麽spring boot怎麽讀取靜態資源?如js文件夾,css文件以及png/jpg圖片呢?怎麽自定義消息轉換器呢?怎麽自定

Spring Boot構建RESTful API與單元測試實戰

一 點睛 1 相關注解 @Controller:修飾class,用來建立處理http請求的物件 @RestController:Spring4之後加入的註解,原來在@Controller中返回json需要@ResponseBody來配合,如果直接用@

Spring Boot提供Actuator對應用系統的自省和監控的整合功能

Health Indicator訪問無結果 錯誤原因: 未匯入依賴包 版本原因導致訪問方式改變了 解決辦法: 匯入依賴包 <dependency> <groupId>o

Spring Boot 入門篇 (二) Spring Boot構建RESTful API與單元測試

http://blog.didispace.com/springbootrestfulapi/ 首先,回顧並詳細說明一下在快速入門中使用的@Controller、@RestController、@RequestMapping註解。如果您對Spring MVC不熟悉並且還沒有嘗試過快速入門案例,建

Spring Boot實戰系列(4)統一異常處理

專案開發中保證零異常似乎是不可能的,不論是系統異常還是程式本身的編碼問題造成的異常資訊都要以一種約定的資料結構返回,友好的處理方式在前後端分離模式下(後端提供API介面給到前端)能大大增加大家的溝通、工作效率。基於Spring Boot進行異常統一處理,本文中主要用到@ControllerAdvice註

Spring Boot 配置 Swagger2 介面文件引擎

手寫文件存在的問題 文件需要更新的時候,需要再次傳送一份給前端,也就是文件更新交流不及時。 介面返回結果不明確 不能直接線上測試介面,通常需要使用工具,比如:Postman 介面文件太多,不好管理 使用 Swagger 解決問題 Swagger 也就是為了

spring boot 配置https 報這個錯誤:java.lang.IllegalArgumentException: Private key must be accompanied by certificate chain

  找了接近半天的時間,原來是那麼小的問題    server.ssl.key-store=test.jksserver.ssl.key-store-password=123456server.ssl.key-store-type=PKCS12server.ssl.key-a

spring-boot構建RESTful Web服務

往後官方demo的筆記不貼程式碼了,只貼連結 官方文件 RESTful Web服務 該服務將處理GET請求/greeting,可選地使用name查詢字串中的引數。該GET請求應該返回200 OK在表示問候的身體與JSON響應。它應該看起來像這樣: { "id": 1, "content

5、spring boot + Maven + Restful filter+interceptor+Aspect

過濾器有兩種建立方式,第一種需要直接實現Filter package com.imooc.filter; import java.io.IOException; import java.util.Date; import javax.servlet.Fi

Spring Boot 構建restful web服務

1.建立依賴檔案 檔名:pom.xml 檔案內容: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://ww

spring boot aop記錄介面呼叫情況

引入依賴 <!-- 引入aop--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>sprin

spring boot專案 前臺介面動態新增div,以及特定點選div事件,delegate()方法。

因為是初次寫前臺介面,在有些地方遇到了很多的問題,其中就包括著後臺得到List,在前臺玄幻div顯示介面,接收資料。一下是迴圈顯示的程式碼。 <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thym

spring-boot提供類可以直接修改tomcat引數,例如port

文件參考:https://docs.spring.io/spring-boot/docs/2.0.1.BUILD-SNAPSHOT/reference/html/ @Bean public ConfigurableServletWebServerFactory webServerFa

spring boot 系列---restful 增、刪、改、查

一 對於Restful 的理解 如下圖:左為傳統風格,右為restful 風格 二、Restful 的:增、刪、改、查 1、增,使用了: @PostMapping:描述了請求的行為 @RequestBody:提交資料為body,使用json提交資料 @Va