springcloud finchley gateway 統一異常處理
全文搜索[@@]搜索重點內容標記
1 . 問題:使用springcloud gateway時,會出現各種系統級異常,默認返回html.
2 . finchley版本的gateway,使用webflux形式作為底層框架,而不是servlet容器,所以常規的異常處理無法使用
翻閱源碼,默認是使用defaulterrorwebexceptionhandler
這個類實現結構如下:
可以實現參考defaulterrorwebexceptionhandler
和abstracterrorwebexceptionhandler
自定義實現errorwebexceptionhandler
,然后,注冊為bean到spring容器中即可(bean name:"errorwebexceptionhandler"
)
具體實現代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
package pro.chenggang.example.spring.cloud.gateway.support; import org.slf4j.logger; import org.slf4j.loggerfactory; import org.springframework.boot.web.reactive.error.errorwebexceptionhandler; import org.springframework.cloud.gateway.support.notfoundexception; import org.springframework.http.httpstatus; import org.springframework.http.mediatype; import org.springframework.http.codec.httpmessagereader; import org.springframework.http.codec.httpmessagewriter; import org.springframework.http.server.reactive.serverhttprequest; import org.springframework.util. assert ; import org.springframework.web.reactive.function.bodyinserters; import org.springframework.web.reactive.function.server.requestpredicates; import org.springframework.web.reactive.function.server.routerfunctions; import org.springframework.web.reactive.function.server.serverrequest; import org.springframework.web.reactive.function.server.serverresponse; import org.springframework.web.reactive.result.view.viewresolver; import org.springframework.web.server.responsestatusexception; import org.springframework.web.server.serverwebexchange; import reactor.core.publisher.mono; import java.util.collections; import java.util.hashmap; import java.util.list; import java.util.map; /** * @classdesc: 統一異常處理,參考{@link org.springframework.web.server.abstracterrorwebexceptionhandler}修改 * @author: chenggang * @createtime: 2018/10/30 */ public class jsonexceptionhandler implements errorwebexceptionhandler { private static final logger log = loggerfactory.getlogger(jsonexceptionhandler. class ); /** * messagereader */ private list<httpmessagereader<?>> messagereaders = collections.emptylist(); /** * messagewriter */ private list<httpmessagewriter<?>> messagewriters = collections.emptylist(); /** * viewresolvers */ private list<viewresolver> viewresolvers = collections.emptylist(); /** * 存儲處理異常后的信息 */ private threadlocal<map<string,object>> exceptionhandlerresult = new threadlocal<>(); /** * 參考abstracterrorwebexceptionhandler * @param messagereaders */ public void setmessagereaders(list<httpmessagereader<?>> messagereaders) { assert .notnull(messagereaders, "'messagereaders' must not be null" ); this .messagereaders = messagereaders; } /** * 參考abstracterrorwebexceptionhandler * @param viewresolvers */ public void setviewresolvers(list<viewresolver> viewresolvers) { this .viewresolvers = viewresolvers; } /** * 參考abstracterrorwebexceptionhandler * @param messagewriters */ public void setmessagewriters(list<httpmessagewriter<?>> messagewriters) { assert .notnull(messagewriters, "'messagewriters' must not be null" ); this .messagewriters = messagewriters; } @override public mono< void > handle(serverwebexchange exchange, throwable ex) { /** * 按照異常類型進行處理 */ httpstatus httpstatus; string body; if (ex instanceof notfoundexception) { httpstatus = httpstatus.not_found; body = "service not found" ; } else if (ex instanceof responsestatusexception) { responsestatusexception responsestatusexception = (responsestatusexception) ex; httpstatus = responsestatusexception.getstatus(); body = responsestatusexception.getmessage(); } else { httpstatus = httpstatus.internal_server_error; body = "internal server error" ; } /** * 封裝響應體,此body可修改為自己的jsonbody */ map<string,object> result = new hashmap<>( 2 , 1 ); result.put( "httpstatus" ,httpstatus); result.put( "body" ,body); /** * 錯誤記錄 */ serverhttprequest request = exchange.getrequest(); log.error( "[全局異常處理]異常請求路徑:{},記錄異常信息:{}" ,request.getpath(),ex.getmessage()); /** * 參考abstracterrorwebexceptionhandler */ if (exchange.getresponse().iscommitted()) { return mono.error(ex); } exceptionhandlerresult.set(result); serverrequest newrequest = serverrequest.create(exchange, this .messagereaders); return routerfunctions.route(requestpredicates.all(), this ::rendererrorresponse).route(newrequest) .switchifempty(mono.error(ex)) .flatmap((handler) -> handler.handle(newrequest)) .flatmap((response) -> write(exchange, response)); } /** * 參考defaulterrorwebexceptionhandler * @param request * @return */ protected mono<serverresponse> rendererrorresponse(serverrequest request) { map<string,object> result = exceptionhandlerresult.get(); return serverresponse.status((httpstatus) result.get( "httpstatus" )) .contenttype(mediatype.application_json_utf8) .body(bodyinserters.fromobject(result.get( "body" ))); } /** * 參考abstracterrorwebexceptionhandler * @param exchange * @param response * @return */ private mono<? extends void > write(serverwebexchange exchange, serverresponse response) { exchange.getresponse().getheaders() .setcontenttype(response.headers().getcontenttype()); return response.writeto(exchange, new responsecontext()); } /** * 參考abstracterrorwebexceptionhandler */ private class responsecontext implements serverresponse.context { @override public list<httpmessagewriter<?>> messagewriters() { return jsonexceptionhandler. this .messagewriters; } @override public list<viewresolver> viewresolvers() { return jsonexceptionhandler. this .viewresolvers; } } } |
注冊bean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
/** * 自定義異常處理[@@]注冊bean時依賴的bean,會從容器中直接獲取,所以直接注入即可 * @param viewresolversprovider * @param servercodecconfigurer * @return */ @primary @bean @order (ordered.highest_precedence) public errorwebexceptionhandler errorwebexceptionhandler(objectprovider<list<viewresolver>> viewresolversprovider, servercodecconfigurer servercodecconfigurer) { jsonexceptionhandler jsonexceptionhandler = new jsonexceptionhandler(); jsonexceptionhandler.setviewresolvers(viewresolversprovider.getifavailable(collections::emptylist)); jsonexceptionhandler.setmessagewriters(servercodecconfigurer.getwriters()); jsonexceptionhandler.setmessagereaders(servercodecconfigurer.getreaders()); log.debug( "init json exception handler instead default errorwebexceptionhandler success" ); return jsonexceptionhandler; } |
[@@]注意事項:
1 .上面為示例代碼,其中牽扯到策略工廠和響應封裝的類,可以自定義實現
2 .注冊bean時依賴的bean,都會從spring容器中獲取到
3 .參考此方法思路,可實現統一異常處理,統一封裝錯誤信息。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://segmentfault.com/a/1190000016854364