spring cloud 网关,依赖于netflix 下的zuul 组件
zuul 的流程是,自定义 了zuulservletfilter和zuulservlet两种方式,让开发者可以去实现,并调用
先来看下zuulservletfilter的实现片段
|
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
|
@override
public void dofilter(servletrequest servletrequest, servletresponse servletresponse, filterchain filterchain) throws ioexception, servletexception {
try {
init((httpservletrequest) servletrequest, (httpservletresponse) servletresponse);
try {
prerouting();
} catch (zuulexception e) {
error(e);
postrouting();
return;
}
// only forward onto to the chain if a zuul response is not being sent
if (!requestcontext.getcurrentcontext().sendzuulresponse()) {
filterchain.dofilter(servletrequest, servletresponse);
return;
}
try {
routing();
} catch (zuulexception e) {
error(e);
postrouting();
return;
}
try {
postrouting();
} catch (zuulexception e) {
error(e);
return;
}
} catch (throwable e) {
error(new zuulexception(e, 500, "uncaught_exception_from_filter_" + e.getclass().getname()));
} finally {
requestcontext.getcurrentcontext().unset();
}
}
|
从上面的代码可以看到,比较关心的是prerouting、routing,postrouting三个方法 ,这三个方法会调用 注册为zuulfilter的子类,首先来看下这三个方法
prerouting: 是路由前会做一些内容
routing():开始路由事项
postrouting:路由结束,不管是否有错误都会经过该方法
那这三个方法是怎么和zuulfilter联系在一起的呢?
先来分析下 prerouting:
|
1
2
3
|
void postrouting() throws zuulexception {
zuulrunner.postroute();
}
|
同时 zuulrunner再来调用
|
1
2
3
|
public void postroute() throws zuulexception {
filterprocessor.getinstance().postroute();
}
|
最终调用 filterprocessor 的 runfilters
|
1
2
3
4
5
6
7
8
9
|
public void preroute() throws zuulexception {
try {
runfilters("pre");
} catch (zuulexception e) {
throw e;
} catch (throwable e) {
throw new zuulexception(e, 500, "uncaught_exception_in_pre_filter_" + e.getclass().getname());
}
}
|
看到了runfilters 是通过 filtertype(pre ,route ,post )来过滤出已经注册的 zuulfilter:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public object runfilters(string stype) throws throwable {
if (requestcontext.getcurrentcontext().debugrouting()) {
debug.addroutingdebug("invoking {" + stype + "} type filters");
}
boolean bresult = false;
//通过stype获取 zuulfilter的列表
list<zuulfilter> list = filterloader.getinstance().getfiltersbytype(stype);
if (list != null) {
for (int i = 0; i < list.size(); i++) {
zuulfilter zuulfilter = list.get(i);
object result = processzuulfilter(zuulfilter);
if (result != null && result instanceof boolean) {
bresult |= ((boolean) result);
}
}
}
return bresult;
}
|
再来看下 zuulfilter的定义
|
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
|
public abstract class zuulfilter implements izuulfilter, comparable<zuulfilter> {
private final dynamicbooleanproperty filterdisabled =
dynamicpropertyfactory.getinstance().getbooleanproperty(disablepropertyname(), false);
/**
* to classify a filter by type. standard types in zuul are "pre" for pre-routing filtering,
* "route" for routing to an origin, "post" for post-routing filters, "error" for error handling.
* we also support a "static" type for static responses see staticresponsefilter.
* any filtertype made be created or added and run by calling filterprocessor.runfilters(type)
*
* @return a string representing that type
*/
abstract public string filtertype();
/**
* filterorder() must also be defined for a filter. filters may have the same filterorder if precedence is not
* important for a filter. filterorders do not need to be sequential.
*
* @return the int order of a filter
*/
abstract public int filterorder();
/**
* by default zuulfilters are static; they don't carry state. this may be overridden by overriding the isstaticfilter() property to false
*
* @return true by default
*/
public boolean isstaticfilter() {
return true;
}
|
只列出了一部分字段,但可以看到filtertype和filterorder两个字段,这两个分别是指定filter是什么类型,排序
这两个决定了实现的zuulfilter会在什么阶段被执行,按什么顺序执行
当选择好已经注册的zuulfilter后,会调用zuulfilter的runfilter
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public zuulfilterresult runfilter() {
zuulfilterresult zr = new zuulfilterresult();
if (!isfilterdisabled()) {
if (shouldfilter()) {
tracer t = tracerfactory.instance().startmicrotracer("zuul::" + this.getclass().getsimplename());
try {
object res = run();
zr = new zuulfilterresult(res, executionstatus.success);
} catch (throwable e) {
t.setname("zuul::" + this.getclass().getsimplename() + " failed");
zr = new zuulfilterresult(executionstatus.failed);
zr.setexception(e);
} finally {
t.stopandlog();
}
} else {
zr = new zuulfilterresult(executionstatus.skipped);
}
}
return zr;
}
|
其中run 是一个zuulfilter的一个抽象方法
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public interface izuulfilter {
/**
* a "true" return from this method means that the run() method should be invoked
*
* @return true if the run() method should be invoked. false will not invoke the run() method
*/
boolean shouldfilter();
/**
* if shouldfilter() is true, this method will be invoked. this method is the core method of a zuulfilter
*
* @return some arbitrary artifact may be returned. current implementation ignores it.
*/
object run();
}
|
所以,实现zuulfilter的子类要重写 run方法,我们来看下 其中一个阶段的实现 predecorationfilter 这个类是spring cloud封装的在使用zuul 作为转发的代码服务器时进行封装的对象,目的是为了决定当前的要转发的请求是按serviceid,http请求,还是forward来作转发
|
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
|
@override
public object run() {
requestcontext ctx = requestcontext.getcurrentcontext();
final string requesturi = this.urlpathhelper.getpathwithinapplication(ctx.getrequest());
route route = this.routelocator.getmatchingroute(requesturi);
if (route != null) {
string location = route.getlocation();
if (location != null) {
ctx.put("requesturi", route.getpath());
ctx.put("proxy", route.getid());
if (!route.iscustomsensitiveheaders()) {
this.proxyrequesthelper
.addignoredheaders(this.properties.getsensitiveheaders().toarray(new string[0]));
}
else {
this.proxyrequesthelper.addignoredheaders(route.getsensitiveheaders().toarray(new string[0]));
}
if (route.getretryable() != null) {
ctx.put("retryable", route.getretryable());
}
// 如果配置的转发地址是http开头,会设置 routehost
if (location.startswith("http:") || location.startswith("https:")) {
ctx.setroutehost(geturl(location));
ctx.addoriginresponseheader("x-zuul-service", location);
}
// 如果配置的转发地址forward,则会设置forward.to
else if (location.startswith("forward:")) {
ctx.set("forward.to",
stringutils.cleanpath(location.substring("forward:".length()) + route.getpath()));
ctx.setroutehost(null);
return null;
}
else {
// 否则以serviceid进行转发
// set serviceid for use in filters.route.ribbonrequest
ctx.set("serviceid", location);
ctx.setroutehost(null);
ctx.addoriginresponseheader("x-zuul-serviceid", location);
}
if (this.properties.isaddproxyheaders()) {
addproxyheaders(ctx, route);
string xforwardedfor = ctx.getrequest().getheader("x-forwarded-for");
string remoteaddr = ctx.getrequest().getremoteaddr();
if (xforwardedfor == null) {
xforwardedfor = remoteaddr;
}
else if (!xforwardedfor.contains(remoteaddr)) { // prevent duplicates
xforwardedfor += ", " + remoteaddr;
}
ctx.addzuulrequestheader("x-forwarded-for", xforwardedfor);
}
if (this.properties.isaddhostheader()) {
ctx.addzuulrequestheader("host", tohostheader(ctx.getrequest()));
}
}
}
else {
log.warn("no route found for uri: " + requesturi);
string fallbackuri = requesturi;
string fallbackprefix = this.dispatcherservletpath; // default fallback
// servlet is
// dispatcherservlet
if (requestutils.iszuulservletrequest()) {
// remove the zuul servletpath from the requesturi
log.debug("zuulservletpath=" + this.properties.getservletpath());
fallbackuri = fallbackuri.replacefirst(this.properties.getservletpath(), "");
log.debug("replaced zuul servlet path:" + fallbackuri);
}
else {
// remove the dispatcherservlet servletpath from the requesturi
log.debug("dispatcherservletpath=" + this.dispatcherservletpath);
fallbackuri = fallbackuri.replacefirst(this.dispatcherservletpath, "");
log.debug("replaced dispatcherservlet servlet path:" + fallbackuri);
}
if (!fallbackuri.startswith("/")) {
fallbackuri = "/" + fallbackuri;
}
string forwarduri = fallbackprefix + fallbackuri;
forwarduri = forwarduri.replaceall("//", "/");
ctx.set("forward.to", forwarduri);
}
return null;
}
|
这个前置处理,是为了后面决定以哪种zuulfilter来处理当前的请求 ,如 simplehostroutingfilter,这个的filtertype是post ,当 “predecorationfilter设置了requestcontext中的 routehost,如 simplehostroutingfilter中的判断
|
1
2
3
4
5
|
@override
public boolean shouldfilter() {
return requestcontext.getcurrentcontext().getroutehost() != null
&& requestcontext.getcurrentcontext().sendzuulresponse();
}
|
在 simplehostroutingfilter中的run中,真正实现地址转发的内容,其实质是调用 httpclient进行请求
|
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
|
@override
public object run() {
requestcontext context = requestcontext.getcurrentcontext();
httpservletrequest request = context.getrequest();
multivaluemap<string, string> headers = this.helper
.buildzuulrequestheaders(request);
multivaluemap<string, string> params = this.helper
.buildzuulrequestqueryparams(request);
string verb = getverb(request);
inputstream requestentity = getrequestbody(request);
if (request.getcontentlength() < 0) {
context.setchunkedrequestbody();
}
string uri = this.helper.buildzuulrequesturi(request);
this.helper.addignoredheaders();
try {
httpresponse response = forward(this.httpclient, verb, uri, request, headers,
params, requestentity);
setresponse(response);
}
catch (exception ex) {
context.set(error_status_code, httpservletresponse.sc_internal_server_error);
context.set("error.exception", ex);
}
return null;
}
|
最后如果是成功能,会调用 注册 为post的zuulfilter ,目前有两个 senderrorfilter 和 sendresponsefilter 这两个了,一个是处理错误,一个是处理成功的结果
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持快网idc。
原文链接:https://www.jianshu.com/p/295e51bc1518
相关文章
- 个人网站服务器域名解析设置指南:从购买到绑定全流程 2025-06-10
- 个人网站搭建:如何挑选具有弹性扩展能力的服务器? 2025-06-10
- 个人服务器网站搭建:如何选择适合自己的建站程序或框架? 2025-06-10
- 64M VPS建站:能否支持高流量网站运行? 2025-06-10
- 64M VPS建站:怎样选择合适的域名和SSL证书? 2025-06-10
- 2025-07-10 怎样使用阿里云的安全工具进行服务器漏洞扫描和修复?
- 2025-07-10 怎样使用命令行工具优化Linux云服务器的Ping性能?
- 2025-07-10 怎样使用Xshell连接华为云服务器,实现高效远程管理?
- 2025-07-10 怎样利用云服务器D盘搭建稳定、高效的网站托管环境?
- 2025-07-10 怎样使用阿里云的安全组功能来增强服务器防火墙的安全性?
快网idc优惠网
QQ交流群
-
2025-05-25 94
-
2025-05-25 102
-
2025-05-26 102
-
2025-05-25 29
-
2025-05-29 105

