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
|
@Override
public Object run() {
RequestContext context = RequestContext.getCurrentContext();
this.helper.addIgnoredHeaders();
try {
// 这里buildCommandContext方法主要是获取前置的Pre设置到ctx中的相关参数,并构造一个RibbonCommandContext返回
RibbonCommandContext commandContext = buildCommandContext(context);
// forward内部其实也是委托给了ribbonCommandFactory的实现者去进行具体调用,
ClientHttpResponse response = forward(commandContext);
// 设置结果 其实就是将结果放到ctx(threadLocal中的zuulResponse属性)进行结果传递。
setResponse(response);
return response;
}
catch (ZuulException ex) {
throw new ZuulRuntimeException(ex);
}
catch (Exception ex) {
throw new ZuulRuntimeException(ex);
}
}
protected RibbonCommandContext buildCommandContext(RequestContext context) {
//...其他代码
// 这里取出来serviceId -> mch-service
String serviceId = (String) context.get(SERVICE_ID_KEY);
// 这里取出来retryable
Boolean retryable = (Boolean) context.get(RETRYABLE_KEY);
// 该值并没有设置过,永远为null
Object loadBalancerKey = context.get(LOAD_BALANCER_KEY);
// 在此方法可以看成是String uri = (String) context.get(REQUEST_URI_KEY);
String uri = this.helper.buildZuulRequestURI(request);
// remove double slashes
uri = uri.replace("//", "/");
long contentLength = useServlet31 ? request.getContentLengthLong(): request.getContentLength();
// 获取完成相关参数构建请求对象
return new RibbonCommandContext(serviceId, verb, uri, retryable, headers, params,
requestEntity, this.requestCustomizers, contentLength, loadBalancerKey);
}
protected ClientHttpResponse forward(RibbonCommandContext context) throws Exception {
...
// 将Context传入到具体的实现中进行包装,返回具体的包装好httpclient的cmmand,而这个command其实就HystrixExecutable接口。
// Zuul提供的默认实现有(HttpClientRibbonCommandFactory,OkHttpRibbonCommandFactory,RestClientRibbonCommandFactory)
RibbonCommand command = this.ribbonCommandFactory.create(context);
try {
// 执行调用并获取到Htpp响应结果
ClientHttpResponse response = command.execute();
this.helper.appendDebug(info, response.getRawStatusCode(), response.getHeaders());
return response;
}
catch (HystrixRuntimeException ex) {
// 异常处理
return handleException(info, ex);
}
}
// 可以看到这里只有http请求异常时,才会触发
protected ClientHttpResponse handleException(Map<String, Object> info,
HystrixRuntimeException ex) throws ZuulException {
int statusCode = HttpStatus.INTERNAL_SERVER_ERROR.value();
Throwable cause = ex;
String message = ex.getFailureType().toString();
ClientException clientException = findClientException(ex);
if (clientException == null) {
clientException = findClientException(ex.getFallbackException());
}
if (clientException != null) {
if (clientException
.getErrorType() == ClientException.ErrorType.SERVER_THROTTLED) {
statusCode = HttpStatus.SERVICE_UNAVAILABLE.value();
}
cause = clientException;
message = clientException.getErrorType().toString();
}
info.put("status", String.valueOf(statusCode));
// 包装了相关信息并向上抛出。
throw new ZuulException(cause, "Forwarding error", statusCode, message);
}
// 设置结果
protected void setResponse(ClientHttpResponse resp)
throws ClientException, IOException {
RequestContext.getCurrentContext().set("zuulResponse", resp);
// 一下方法的调用会将返回的body的inputStream设置到ctx
// context.setResponseDataStream(entity); 方便后面的fiter使用
this.helper.setResponse(resp.getRawStatusCode(),
resp.getBody() == null ? null : resp.getBody(), resp.getHeaders());
}
|