2)如果路由是通过URL指定的,那么需要配置zuul.host.connect-timeout-millis和zuul.host.socket-timeout-millis
如果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处理这些请求,可以通过提供自定义WebMvcConfigurer
bean来完成
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping(“/path-1/**”)
.allowedOrigins(“https://allowed-origin.com”)
.allowedMethods(“GET”, “POST”);
}
};
}
在上面的示例中,我们允许GET
和POST
方法从allowed-origin.com
将跨域请求发送到以开头的端点path-1
。您可以使用/**
映射将CORS配置应用于特定的路径模式,也可以将其整体应用于整个应用程序。您可以自定义属性:allowedOrigins
,allowedMethods
,allowedHeaders
,exposedHeaders
,allowCredentials
并maxAge
通过此配置。
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中修改请求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 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开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
最后希望可以帮助到大家!
千千万万要记得:多刷题!!多刷题!!
之前算法是我的硬伤,后面硬啃了好长一段时间才补回来,算法才是程序员的灵魂!!!!
篇幅有限,以下只能截图分享部分的资源!!
(1)多线程(这里以多线程为代表,其实整理了一本JAVA核心架构笔记集)
(2)刷的算法题(还有左神的算法笔记)
(3)面经+真题解析+对应的相关笔记(很全面)
(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、安卓逆向、云计算