springboot自定義http反饋狀態碼

最近在開發一些http server類型程序,經過spring boot構建一些web程序,這些web程序之間經過http進行數據訪問、共享,以下圖,html

image

假設如今client發起一次保存數據的請求到server,server可能會返回以下相似的數據java

{
	"status":1,
	"message":"xxxxxx"
}

而後client經過解析json得到status來判斷當前的請求操做是否成功,開發過程當中經過都是這麼作的,可是這樣在restful設計中不怎麼好,其實這個status字段的表達徹底能夠經過http status來表示,相似40四、500、502這種都有明確的定義而且相互理解、溝通起來也方便。web

文章主要記錄一下我是如何在spring boot中實現自定反饋狀態碼的,以及我找到的三種實現方式。spring

第一種,使用**@ResponseStatus**。這是一個註解,能夠做用在方法和類上面,以下使用,json

在方法上使用方式,api

@RequestMapping(value = "/user", method = RequestMethod.GET)
	@ResponseStatus(code=HttpStatus.INTERNAL_SERVER_ERROR,reason="server error")
	public String getUser(){
		return "im zhangsan";
	}

啓動web程序,經過postman訪問http://127.0.0.1:8100/user,會出現下面結果,restful

{
    "timestamp": 1497850427325,
    "status": 500,
    "error": "Internal Server Error",
    "message": "server error",
    "path": "/user"
}

這裏我一開始以爲很奇怪,爲何個人getUser方法中沒有錯誤,結果仍是出現了500錯誤?緣由就是@ResponseStatus註解的問題,我後面猜想它會強制的將映射轉化成500的狀態碼。這種應用場景我想不太明白在什麼地方會用到。mvc

在類中使用方式,app

@ResponseStatus(code=HttpStatus.INTERNAL_SERVER_ERROR,reason="111")
public class ServerException extends Exception {

}

這種使用方式就是將自定義異常和狀態碼結合在一塊兒,合理使用自定義異常機制能夠最大化的提升程序的健壯性,下面看如何使用,框架

@RequestMapping(value = "/user", method = RequestMethod.GET)
public String getUser(@RequestParam String userName) throws ServerException{
	if(StringUtils.isEmpty(userName)){
		throw new ServerException();
	}
	return "im zhangsan";
}

這段代碼的意思是當userName字段爲null的時候會拋出ServerException異常,可是ServerException類被標記了@ResponseStatus註解,所以會直接報500錯誤,若是以爲500不適合還能夠定義其它的錯誤代碼。

這種方式看着已經很好了,能夠按照邏輯自定義反饋碼,程序夠健壯。這種方式也有很差地方,若是反饋碼太多須要定義太多的異常類,而且錯誤內容reason仍是不能手動定義。

到這裏,我基本上放棄了@ResponseStatus的使用了。

第二種,使用HttpServletResponse,HttpServletResponse是javax.servlet下的一個接口,以下使用,

@RequestMapping(value = "/user", method = RequestMethod.GET)
public void getUser(HttpServletResponse response) throws IOException{
	response.setStatus(500);
	response.getWriter().append("server error");
}

這種方式能夠很好的實現同時知足自定義反饋碼+消息內容,通常的實現方式也都是這樣。可是這樣也不是太好,

  1. 在括號內建立了一個response內置變量,這樣顯得不夠美觀,反而有些多餘。
  2. 在方法中調用了源生的方法來設置反饋碼和消息體,而且若是須要返回json格式數據還須要設置response.setContentType("application/json");和response.setCharacterEncoding("UTF-8");,這樣作有些多餘,重複的工做太多,雖然能夠進行封裝。
  3. 最嚴重的問題這個方法必須是void類型,不然就會和@ResponseBody出現衝突,其次就是不能利用@ResponseBody自動封裝json的特性,在spring mvc框架中若是在方法上加上@ResponseBody是能夠對返回值自動進行json封裝的。

再找找其餘的,若是沒有找到,估計也只能接受這個不完美的東西了。

後來在翻閱spring boot文檔的時候找到了ResponseEntity這麼一個東西,這就是我要說的第三種方式。

第三種,使用ResponseEntity

很少說,直接上代碼,

@RequestMapping(value = "/user", method = RequestMethod.GET)
public ResponseEntity<Map<String,Object>> getUser() throws IOException{
	Map<String,Object> map = new HashMap<String,Object>();
	map.put("name", "zhangsan");
	return new ResponseEntity<Map<String,Object>>(map,HttpStatus.OK);
}

經過postman查看返回結果,以下,

{
    "name": "zhangsan"
}

能夠直接將map對象幫我轉化成json對象,而且能夠得到自定義狀態碼,很好,很強大。

這種方式很和我意,

  1. 不須要多於的HttpServletResponse,看着很乾淨。
  2. 能夠充分利用@ResponseBody註解,直接將個人返回值幫我轉化成json對象。
  3. 在設置返回值的時候同時還能夠設置http反饋碼,HttpStatus是springframework提供的一個枚舉類,裏面封裝了全部的http反饋碼,方便使用命名統一,不會有任何歧義。

相比於前面兩種,這種方式很對我胃口。

仔細看了ResponseEntity的說明,發現spring mvc其它不少地方也都有使用,以下,下面內容摘自org.springframework.http.ResponseEntity文件註釋,

In RestTemplate, this class is returned by getForEntity() and exchange():

ResponseEntity<String> entity = template.getForEntity("http://example.com", String.class);
 String body = entity.getBody();
 MediaType contentType = entity.getHeaders().getContentType();
 HttpStatus statusCode = entity.getStatusCode();

Can also be used in Spring MVC, as the return value from a @Controller method:

@RequestMapping("/handle")
 public ResponseEntity<String> handle() {
   URI location = ...;
   HttpHeaders responseHeaders = new HttpHeaders();
   responseHeaders.setLocation(location);
   responseHeaders.set("MyResponseHeader", "MyValue");
   return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED);
 }

這就是上面說過的。

Or, by using a builder accessible via static methods:

@RequestMapping("/handle")
 public ResponseEntity<String> handle() {
   URI location = ...;
   return ResponseEntity.created(location).header("MyResponseHeader", "MyValue").body("Hello World");
 }

自定義http反饋碼在設計優良的restful api中起到關鍵做用,http反饋碼是業內統1、共識的,建議在儘可能不要經過解析json來得到status判斷操做結果。

 

完。

相關文章
相關標籤/搜索