java面试太难,网关 Spring Cloud Zuul 常见功能介绍,java基础知识面试题

2)如果路由是通过URL指定的,那么需要配置zuul.host.connect-timeout-millis和zuul.host.socket-timeout-millis

重写头部Location字段


如果Zuul在一个web应用前面,那么你需要重写Location头部当你的web应用通过HTTP状态码3XX重定向。否则,浏览器会重定向到web应用的URL而不是Zuul的URL。

可以通过配置一个LocationRewriteFilter类型的Zuul过滤器来重写Location头部到Zuul的URL。它还恢复了删除的全局前缀和特定于路由的前缀。如下

@Configuration

@EnableZuulProxy

public class ZuulConfig {

@Bean

public LocationRewriteFilter locationRewriteFilter() {

return new LocationRewriteFilter();

}

}

注意:要非常小心使用这个过滤器,因为它会作用于所有响应码为3XX的Location头部,这可能在某些场合不适合。比如要重定向到一个外部地址。

跨域请求


默认情况下,Zuul将所有跨源请求(CORS)路由到服务。如果您想让Zuul处理这些请求,可以通过提供自定义WebMvcConfigurerbean来完成

@Bean

public WebMvcConfigurer corsConfigurer() {

return new WebMvcConfigurer() {

public void addCorsMappings(CorsRegistry registry) {

registry.addMapping(“/path-1/**”)

.allowedOrigins(“https://allowed-origin.com”)

.allowedMethods(“GET”, “POST”);

}

};

}

在上面的示例中,我们允许GETPOST方法从allowed-origin.com将跨域请求发送到以开头的端点path-1。您可以使用/**映射将CORS配置应用于特定的路径模式,也可以将其整体应用于整个应用程序。您可以自定义属性:allowedOriginsallowedMethodsallowedHeadersexposedHeadersallowCredentialsmaxAge通过此配置。

度量指标


Zuul在Actuator metrics端点下提供metrics,当路由请求出现失败时。可以通过/actuator/metrics端点查看。metrics名称的格式为ZUUL::EXCEPTION:errorCause:statusCode。

限流


https://www.baeldung.com/spring-cloud-zuul-rate-limit

com.marcosbarbero.cloud

spring-cloud-zuul-ratelimit

2.2.0.RELEASE

zuul:

routes:

serviceSimple:

path: /greeting/simple

url: forward:/

serviceAdvanced:

path: /greeting/advanced

url: forward:/

ratelimit:

enabled: true

repository: JPA

policy-list:

serviceSimple:

  • limit: 5

refresh-interval: 60

type:

  • origin

serviceAdvanced:

  • limit: 1

refresh-interval: 2

type:

  • origin

strip-prefix: true

为_serviceSimple_ 端点增加了每60秒5个请求的速率限制。相反, _serviceAdvanced_的速率限制为每2秒1个请求

The type configuration specifies which rate limit approach we want to follow. Here are the possible values:

  • origin – rate limit based on the user origin request

  • url – rate limit based on the request path of the downstream service

  • user – rate limit based on the authenticated username or ‘anonymous’

  • No value – acts as a global configuration per service. To use this approach just don’t set param ‘type’

在ZuulFilter中修改请求和相应


在ZuulFilter中修改请求Resquest

public class CustomZuulFilter extends ZuulFilter {

@Override

public Object run() {

RequestContext ctx = RequestContext.getCurrentContext();

ctx.addZuulRequestHeader(“Test”, “TestSample”);

return null;

}

@Override

public boolean shouldFilter() {

return true;

}

// …

}

下游服务取值

@RestController

public class FooController {

@GetMapping(“/foos/{id}”)

public Foo findById(

@PathVariable long id, HttpServletRequest req, HttpServletResponse res) {

if (req.getHeader(“Test”) != null) {

res.addHeader(“Test”, req.getHeader(“Test”));

}

}

}

在ZuulFilter中修改响应Response

public class ResponseFilter extends ZuulFilter {

@Override

public String filterType() {

return POST_TYPE;

}

@Override

public int filterOrder() {

return 0;

}

@Override

public boolean shouldFilter() {

return true;

}

@Override

public Object run() throws ZuulException {

RequestContext context = RequestContext.getCurrentContext();

try (final InputStream responseDataStream = context.getResponseDataStream()) {

if(responseDataStream == null) {

logger.info(“BODY: {}”, “”);

return null;

}

String responseData = CharStreams.toString(new InputStreamReader(responseDataStream, “UTF-8”));

logger.info(“BODY: {}”, responseData);

context.setResponseBody(responseData);//重点 将响应主体添加回上下文中

} catch (Exception e) {

throw new ZuulException(e, INTERNAL_SERVER_ERROR.value(), e.getMessage());

}

return null;

}

}

我们使用context.setResponseBody(responseData)将响应主体添加回上下文中进行处理

zuul开发指南


Zuul Servlet

Zuul的实现是一个Servlet。通常情况下,Zuul是嵌入到Spring分发机制中的。Spring MVC会掌控路由。这种情况下,Zuul会缓存请求。如果有一种情况是穿过Zuul但是不要缓存(例如大文件的上传),这时可以使用一种独立于Spring分发器的外部Servlet。默认情况,这个Servlet的地址是/zuul。也可以通过zuul.servlet-path属性来修改。

Zuul RequestContext

Zuul使用RequestContext在不同的过滤器中传递信息。它的数据保存在特定于每个请求的ThreadLocal中.它存储的信息有:路由请求到何处,错误,HttpServletRequest 和 HttpServletResponse。

RequestContext继承ConcurrentHashMap,所以它可以存储任何信息。FilterConstants保存了那些被过滤器使用的key。

@EnableZuulProxy vs. @EnableZuulServer

Spring Cloud Netflix安装了一系列过滤器,安装了哪些过滤器依赖于你使用哪种注解来开启Zuul的。@EnableZuulProxy是@EnableZuulServer的超集。换句话说,@EnableZuulProxy包含了@EnableZuulServer中的过滤器。

在“proxy”模式中的额外过滤器开启了路由功能。所以如果想要一个“空白”的Zuul,就使用@EnableZuulServer。

@EnableZuulServer Filters

@EnableZuulServer创建一个SimpleRouteLocator(它从Spring Boot配置文件中加载路由定义)。

安装的过滤器(作为普通的spring bean):

1)Pre filters:

ServletDetectionFilter:检测请求是否是通过Spring Dispatcher,设置FilterConstants.IS_DISPATCHER_SERVLET_REQUEST_KEY的布尔值。

FormBodyWrapperFilter:解析表单数据,并且为下游请求重新编码这些数据。

DebugFilter:如果请求参数中设置了debug,则RequestContext.setDebugRouting()和RequestContext.setDebugRequest()都设置为true。

2)Route filters:

SendForwardFilter:使用RequestDispatcher转发请求。转发地址存储在RequestContext的FilterConstants.FORWARD_TO_KEY属性中。

3)Post filters:

SendResponseFilter:将代理请求的响应写入到当前的响应中。

4)Error filters:

SendErrorFilter:如果RequestContext.getThrowable()不是null,则转发到/error(默认)。也可以error.path设置转发路径。

@EnableZuulProxy Filters

创建一个 DiscoveryClientRouteLocator(从DiscoveryClient(例如Eureka)和配置文件中加载路由定义)。为每个服务发现客户端中的serviceId都会创建一个路由。当有新服务添加时,路由就会刷新。

除了上面的过滤器外,还有额外的过滤器:

1)Pre filters:

PreDecorationFilter:根据提供的RouteLocator来决定如何路由,并且路由到何处。并且为下游服务设置了一些代理相关的头部。

2)Route filters:

RibbonRoutingFilter:使用Ribbon、Hystrix和可插入的HTTP客户端发送请求。服务ID存储在RequestContext的FilterConstants.SERVICE_ID_KEY键中。

这个过滤器可以使用不同的HTTP客户端:

1️⃣Apache HttpClient:默认客户端

2️⃣Squareup OkHttpClient v3:添加com.squareup.okhttp3:okhttp依赖,并且设置ribbon.okhttp.enabled=true。

3️⃣Netflix Ribbon HTTP client:设置ribbon.restclient.enabled=true。但是这个客户端有一些限制,它不支持PATCH方法,但是有内建的重试机制。

SimpleHostRoutingFilter:通过Apache HttpClient向预定的url发送请求。URL在RequestContext.getRouteHost()中。

自定义Zuul过滤器示例

下面的大多数“如何编写”示例都包含在示例Zuul过滤器项目中。在该存储库中也有一些处理请求或响应正文的示例。

本节包括以下示例:

Pre filters为在RequestContext中设置数据,给下游的过滤器使用。主要用途就设置一些route过滤器需要的信息。如下:

public class QueryParamPreFilter extends ZuulFilter {

@Override

public int filterOrder() {

return PRE_DECORATION_FILTER_ORDER - 1; // run before PreDecoration

}

@Override

public String filterType() {

return PRE_TYPE;

}

@Override

public boolean shouldFilter() {

RequestContext ctx = RequestContext.getCurrentContext();

return !ctx.containsKey(FORWARD_TO_KEY) // a filter has already forwarded

&& !ctx.containsKey(SERVICE_ID_KEY); // a filter has already determined serviceId

}

@Override

public Object run() {

RequestContext ctx = RequestContext.getCurrentContext();

HttpServletRequest request = ctx.getRequest();

if (request.getParameter(“sample”) != null) {

// put the serviceId in RequestContext

ctx.put(SERVICE_ID_KEY, request.getParameter(“foo”));

}

return null;

}

}

上面的过滤器使用sample请求参数填充SERVICE_ID_KEY。实际上不应该做这种直接映射,Service ID应该从sample的值中查找。

现在,SERVICE_ID_KEY已经被填充,所以PreDecorationFilter将不会执行,RibbonRoutingFilter会执行。

注意:如果想路由到一个完整的URL,调用ctx.setRouteHost(url)。

要修改路由过滤器转发到的路径,请设置REQUEST_URI_KEY。

Route filters在pre filters后执行。它转发请求到其他服务。这里的大部分工作是将请求和响应数据转换到客户机所需的模型。

public class OkHttpRoutingFilter extends ZuulFilter {

@Autowired

private ProxyRequestHelper helper;

@Override

public String filterType() {

return ROUTE_TYPE;

}

@Override

public int filterOrder() {

return SIMPLE_HOST_ROUTING_FILTER_ORDER - 1;

}

@Override

public boolean shouldFilter() {

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

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

}

@Override

public Object run() {

OkHttpClient httpClient = new OkHttpClient.Builder()

// customize

.build();

RequestContext context = RequestContext.getCurrentContext();

HttpServletRequest request = context.getRequest();

String method = request.getMethod();

String uri = this.helper.buildZuulRequestURI(request);

Headers.Builder headers = new Headers.Builder();

Enumeration headerNames = request.getHeaderNames();

while (headerNames.hasMoreElements()) {

String name = headerNames.nextElement();

Enumeration values = request.getHeaders(name);

while (values.hasMoreElements()) {

String value = values.nextElement();

headers.add(name, value);

}

}

InputStream inputStream = request.getInputStream();

RequestBody requestBody = null;

if (inputStream != null && HttpMethod.permitsRequestBody(method)) {

MediaType mediaType = null;

if (headers.get(“Content-Type”) != null) {

mediaType = MediaType.parse(headers.get(“Content-Type”));

}

requestBody = RequestBody.create(mediaType, StreamUtils.copyToByteArray(inputStream));

}

Request.Builder builder = new Request.Builder()

.headers(headers.build())

.url(uri)

.method(method, requestBody);

Response response = httpClient.newCall(builder.build()).execute();

LinkedMultiValueMap<String, String> responseHeaders = new LinkedMultiValueMap<>();

for (Map.Entry<String, List> entry : response.headers().toMultimap().entrySet()) {

responseHeaders.put(entry.getKey(), entry.getValue());

}

this.helper.setResponse(response.code(), response.body().byteStream(),

responseHeaders);

context.setRouteHost(null); // prevent SimpleHostRoutingFilter from running

return null;

}

}

上面的过滤器将Servlet请求信息转换到OkHttp3请求信息中,并且发送一个HTTP请求,然后将OkHttp3响应信息转换到Servlet响应信息中。

Post filters主要是用来修改响应。下面的例子中在响应头中添加一个X-Sample头部并且设置为UUID。

public class AddResponseHeaderFilter extends ZuulFilter {

@Override

public String filterType() {

return POST_TYPE;

}

@Override

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

最后希望可以帮助到大家!

千千万万要记得:多刷题!!多刷题!!

之前算法是我的硬伤,后面硬啃了好长一段时间才补回来,算法才是程序员的灵魂!!!!

篇幅有限,以下只能截图分享部分的资源!!

(1)多线程(这里以多线程为代表,其实整理了一本JAVA核心架构笔记集)

image

(2)刷的算法题(还有左神的算法笔记)

image

(3)面经+真题解析+对应的相关笔记(很全面)

image

(4)视频学习(部分)

ps:当你觉得学不进或者累了的时候,视频是个不错的选择

在这里,最后只一句话:祝大家offer拿到手软!!

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

新**

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-WGsRbOtO-1712434053830)]

最后希望可以帮助到大家!

千千万万要记得:多刷题!!多刷题!!

之前算法是我的硬伤,后面硬啃了好长一段时间才补回来,算法才是程序员的灵魂!!!!

篇幅有限,以下只能截图分享部分的资源!!

(1)多线程(这里以多线程为代表,其实整理了一本JAVA核心架构笔记集)

[外链图片转存中…(img-byNLwP6R-1712434053831)]

(2)刷的算法题(还有左神的算法笔记)

[外链图片转存中…(img-KDk5UHp3-1712434053831)]

(3)面经+真题解析+对应的相关笔记(很全面)

[外链图片转存中…(img-ZI7xW96L-1712434053831)]

(4)视频学习(部分)

ps:当你觉得学不进或者累了的时候,视频是个不错的选择

在这里,最后只一句话:祝大家offer拿到手软!!

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

  • 10
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值