日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > javascript >内容正文

javascript

java http请求原理_浅谈Spring Cloud zuul http请求转发原理

發(fā)布時(shí)間:2024/9/27 javascript 183 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java http请求原理_浅谈Spring Cloud zuul http请求转发原理 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

spring cloud 網(wǎng)關(guān),依賴于netflix 下的zuul 組件

zuul 的流程是,自定義 了ZuulServletFilter和zuulServlet兩種方式,讓開(kāi)發(fā)者可以去實(shí)現(xiàn),并調(diào)用

先來(lái)看下ZuulServletFilter的實(shí)現(xiàn)片段

@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();

}

}

從上面的代碼可以看到,比較關(guān)心的是preRouting、routing,postRouting三個(gè)方法 ,這三個(gè)方法會(huì)調(diào)用 注冊(cè)為ZuulFilter的子類,首先來(lái)看下這三個(gè)方法

preRouting: 是路由前會(huì)做一些內(nèi)容

routing():開(kāi)始路由事項(xiàng)

postRouting:路由結(jié)束,不管是否有錯(cuò)誤都會(huì)經(jīng)過(guò)該方法

那這三個(gè)方法是怎么和ZuulFilter聯(lián)系在一起的呢?

先來(lái)分析下 preRouting:

void postRouting() throws ZuulException {

zuulRunner.postRoute();

}

同時(shí) ZuulRunner再來(lái)調(diào)用

public void postRoute() throws ZuulException {

FilterProcessor.getInstance().postRoute();

}

最終調(diào)用 FilterProcessor的 runFilters

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 是通過(guò) filterType(pre ,route ,post )來(lái)過(guò)濾出已經(jīng)注冊(cè)的 ZuulFilter:

public Object runFilters(String sType) throws Throwable {

if (RequestContext.getCurrentContext().debugRouting()) {

Debug.addRoutingDebug("Invoking {" + sType + "} type filters");

}

boolean bResult = false;

//通過(guò)sType獲取 zuulFilter的列表

List 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;

}

再來(lái)看下 ZuulFilter的定義

public abstract class ZuulFilter implements IZuulFilter, Comparable {

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兩個(gè)字段,這兩個(gè)分別是指定filter是什么類型,排序

這兩個(gè)決定了實(shí)現(xiàn)的ZuulFilter會(huì)在什么階段被執(zhí)行,按什么順序執(zhí)行

當(dāng)選擇好已經(jīng)注冊(cè)的ZuulFilter后,會(huì)調(diào)用ZuulFilter的runFilter

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 是一個(gè)ZuulFilter的一個(gè)抽象方法

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();

}

所以,實(shí)現(xiàn)ZuulFilter的子類要重寫 run方法,我們來(lái)看下 其中一個(gè)階段的實(shí)現(xiàn) PreDecorationFilter 這個(gè)類是Spring Cloud封裝的在使用Zuul 作為轉(zhuǎn)發(fā)的代碼服務(wù)器時(shí)進(jìn)行封裝的對(duì)象,目的是為了決定當(dāng)前的要轉(zhuǎn)發(fā)的請(qǐng)求是按ServiceId,Http請(qǐng)求,還是forward來(lái)作轉(zhuǎn)發(fā)

@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());

}

// 如果配置的轉(zhuǎn)發(fā)地址是http開(kāi)頭,會(huì)設(shè)置 RouteHost

if (location.startsWith("http:") || location.startsWith("https:")) {

ctx.setRouteHost(getUrl(location));

ctx.addOriginResponseHeader("X-Zuul-Service", location);

}

// 如果配置的轉(zhuǎn)發(fā)地址forward,則會(huì)設(shè)置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進(jìn)行轉(zhuǎn)發(fā)

// 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;

}

這個(gè)前置處理,是為了后面決定以哪種ZuulFilter來(lái)處理當(dāng)前的請(qǐng)求 ,如 SimpleHostRoutingFilter,這個(gè)的filterType是post ,當(dāng) ``PreDecorationFilter設(shè)置了requestContext中的 RouteHost,如 SimpleHostRoutingFilter中的判斷

@Override

public boolean shouldFilter() {

return RequestContext.getCurrentContext().getRouteHost() != null

&& RequestContext.getCurrentContext().sendZuulResponse();

}

在 SimpleHostRoutingFilter中的run中,真正實(shí)現(xiàn)地址轉(zhuǎn)發(fā)的內(nèi)容,其實(shí)質(zhì)是調(diào)用 httpClient進(jìn)行請(qǐng)求

@Override

public Object run() {

RequestContext context = RequestContext.getCurrentContext();

HttpServletRequest request = context.getRequest();

MultiValueMap headers = this.helper

.buildZuulRequestHeaders(request);

MultiValueMap 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;

}

最后如果是成功能,會(huì)調(diào)用 注冊(cè) 為post的ZuulFilter ,目前有兩個(gè) SendErrorFilter 和 SendResponseFilter 這兩個(gè)了,一個(gè)是處理錯(cuò)誤,一個(gè)是處理成功的結(jié)果

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

總結(jié)

以上是生活随笔為你收集整理的java http请求原理_浅谈Spring Cloud zuul http请求转发原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。