理解成为nginx即可,只要代理端,无需客户端 @EnableZuulProxy
做了zuul路由之后可以用,也可以不用直接调用原服务
1,反向代理----路由部分:
zuul.routes.user-service.path=/user-service/**
zuul.routes.user-service.serviceId=user-service
zuul.routes.user-service-ext.path=/user-service/ext/**
zuul.routes.user-service-ext.serviceId=user-service-ext
这个时候,调用user-service-ext服务的URL路径实际上会同时被/user-service/**和/user-service/ext/**两个表达式所匹配。在逻辑上,API网关服务需要优先选择/user-service/ext/**路由,然后再匹配/user-service/**路由才能实现上述需求。但是如果使用上面的配置方式,实际上是无法保证这样的路由优先顺序的。
有冲突部分按照匹配的顺序来,在请求路径获取到第一个匹配的路由规则之后就会返回并结束匹配过程。所以当存在多个匹配的路由规则时,匹配结果完全取决于路由规则的保存顺序。
zuul:
routes:
users: ---随便写的便于看分类,逻辑打包配置(里面的是局部变量只适用一个分类中),逻辑服务名
path: /myusers/**
serviceId: users_service---这个才是服务名,不写上下文是/ 经过了feign就可以用负载,实际服务名---myusers被替代部分
zuul:
routes:
users:
path: /myusers/**
url: http://example.com/users_service ---url的方式的话上下文就是整个url
zuul有动态路由静态路由:
动态路由---经过注册中心监控的,-----适用serverId方式
静态路由---不经过注册中心监控即直连的-----适用serverId,url方式,此时需独立使用ribbon,关闭ureka
zuul路由的几个配置参数
1.静态路由
zuul:
routes:
myroute1:
path: /mypath/**
url: http://localhost:8080(注意这里url要http://开头)
2.静态路由+ribbon负载均衡/故障切换
zuul:
routes:
myroutes1:
path: /mypath/**
serviceId: myserverId
myserverId:
ribbon:
listOfServers: localhost:8080, localhost:8081 ---静态路由指定的负载服务
ribbon:
eureka:
enabled: false
3.动态路由+ribbon负载均衡/故障切换
zuul:
routes:
myroutes1:
path: /mypath/**
serviceId: myserviceId
eureka:
client:
serviceUrl:
defaultZne:xxx
4.路由匹配的一些配置
stripPrefix=true,转发会过滤掉前缀。-------------默认会去了zuul特征路径的,到了实际服务端就是去了之后的
path: /myusers/**,默认时转发到服务的请求是/**,如果stripPrefix=false,转发的请求是/myusers/**
zuul.prefix=/api会对所有的path增加一个/api前缀
ignoredPatterns: /**/admin/**过滤掉匹配的url
route:
users: /myusers/**会匹配所有/myusers/**的url,但由于ignoredPatterns, /myusers/**/admin/**的请求不会被转发,而是直接由zuul里的接口接收
匹配顺序
path:/myusers/**
path:/**如果是在application.yml中配置的,那么会优先匹配/myusers/**
但如果是applicaiton.properties配置的,那么可能导致/myusers/**被/**覆盖
ignored-Services: ‘*‘对于自动发现的services,除了route中明确指定的,其他都会被忽略
5.请求头过滤
route.sensitiveHeaders: Cookie,Set-Cookie,Authorization
默认就有这三个请求头,意思是不向下游转发请求这几个头
zuul.ignoredHeaders 是一个全局设置,而route.sensitiveHeaders是局部设置
zuul过滤器
标准的zuul过滤器有4中,分别对应一次路由转发的几个关键点;
pre: 在路由转发之前起作用
routing: 在路由时其作用
post: 在把结果返回给浏览器时起作用
error: 在整个路由阶段,出现异常时起作用
如果要分析前端传来的参数,验证前端身份等对前端参数的操作,显然是用pre过滤器
如果是要对返回给前端的结果进行操作或者分析,显然是用post过滤器
编写自定义路由器
public class MyFilter extends ZuulFilter{
filterType()重写,返回这个过滤器的类型
filterOrder()重写,返回这个过滤器在过滤器链的顺序
shouldFilter() true启动
run()具体逻辑
}
属性在不同文件中的优先级:
1,application.yml 同样的属性匹配到第一个即可
2,application.properties 同样的属性后面的覆盖前面的
3,application.yml:中legacy的优先级和.properties不一样
zuul:
routes:
users:
path: /myusers/**
legacy:
path: /**
如果要使用属性文件,则legacy路径可能会在users路径前面展开,从而使users路径不可达。
参考:
https://blog.csdn.net/qq_31482599/article/details/80379513
2,zuul客户端---连接zuul服务端的工具
1,默认使用的是Apache http
2,需要使用RestClient或使用okhttp3.OkHttpClient 需要设置相应的属性 ribbon.restclient.enabled=true或ribbon.okhttp.enabled=true
3,敏感属性的传递
一 敏感Header的设置
一般来说,可在同一系统中的服务之间共享Header.不过应尽量防止让一些敏感的Header外泄。因此,在很多场景下,需要通过为路由指定一系列敏感Header列表。例如:
即:
zuul向后端服务转发请求的时候是否传递敏感信息
网关配置:
zuul:
routes:
users:
path: /myusers/**
# 不向后端服务传递的敏感头信息
sensitiveHeaders: Cookie,Set-Cookie,Authorization
url: https://downstream
这样就可为users微服务指定敏感Header了。
也可用zuul.sensitiveHeaders全局指定敏感Header,例如:
zuul
sensitiveHeaders: Cookie,Set-Cookie,Authorization #默认是Cookie,Set-Cookie,Authorization
需要注意的是,如果使用zuul.routes.*.sensitiveHeaders的配置方式,会覆盖掉全局的配置。
二 忽略Header
可使用zuul.ignoredHeaders属性丢弃一些Header,例如:
zuul
ignoredHeaders: Header1,Header2
这样设置后,Header1和Header2将不会传播到其他微服务中。
默认情况下,zuul.ignoredHeaders是空值,但如果Spring Security在项目的classpath中,那么zuul.ignoredHeaders的默认值就是Pragma,Cache-Control,X-Frame-Options,X-Content-Type-Options,X-XSS-Protection,Expires。所以,当Spring Security在项目classpath中,同时又需要使用下游微服务的Spring Security的Header时,可以将zuul.ignoreSecurityHeaders设置为false。
zuul转发时忽略敏感信息的原理:
我们是使用spring cloud zuul作为api-gateway实践中,发现默认zuul会过滤掉cookie等header信息,有些业务场景需要传递这些信息该怎么处理呢?
处理方式 在api-gateway的application.properties文件中添加 zuul.sensitive-headers=
问题原因
负责根据ServiceId来路由的RibbonRoutingFilter在route之前会调用ProxyRequestHelper的buildZuulRequestHeaders(request)来重新组装一个新的Header。
在buildZuulRequestHeaders方法中会对RequsetHeader中的每一项调用isIncludedHeader(name)来判断当前项是否应该留在新的Header中,如下图,如果当前项在IGNORED_HEADERS(需要忽略的信息)中,就不会在新header中保留。
PreDecorationFilter过滤器会调用ProxyRequestHelper的addIgnoredHeaders方法把敏感信息(ZuulProperties的sensitiveHeaders属性)添加到请求上下文的IGNORED_HEADERS中
sensitiveHeaders的默认值初始值是"Cookie", "Set-Cookie", "Authorization"这三项,可以看到Cookie被列为了敏感信息,所以不会放到新header中
三 参考
http://cloud.spring.io/spring-cloud-static/Camden.SR2/#_zuul_http_client
https://github.com/spring-cloud/spring-cloud-netflix/issues/1487
https://blog.csdn.net/lindan1984/article/details/79308396
4,被忽略的标题
这个是全局的忽略上面的敏感字段最终会汇集到这里
zuul.ignoredHeaders
5, 线路端点--可以查看当前服务的映射列表
http://localhost:4534/actuator/routes---get访问查看,post访问更新
6,窒息模式和本地跳转(Strangulation Patterns and Local Forwards)
一个老旧系统逐步被代替的过程,用yml文件的顺序优先匹配原则legacy逻辑分类是旧的系统,path匹配所有请求,之后做出一部分新的系统,将其路由
放在上面,就实现了逐步替换
application.yml
zuul:
routes:
first:
path: /first/**
url: http://first.example.com
second:
path: /second/**
url: forward:/second
third:
path: /third/**
url: forward:/3rd
legacy:
path: /**
url: http://legacy.example.com
7,通过zuul传输文件
小文件可以自由上传,大于10m的文件需要设置/zuul前缀,或者通过zuul.servlet-path自定义前缀--添加/zuul前缀是指用zuul-servlet来实现传输
注意文件太大设置超时
stripPrefix=true,转发会过滤掉前缀。-------------默认会去了zuul特征路径的,到了实际服务端就是去了之后的
例如:假设 zuul.routes.file-upload = /file-upload/**,如果 http://{HOST}:{PORT}/uoload 是微服务 file-upload 上传路径,则可以使用 Zuul 的 /zuul/file-upload/upload 路径上传大文件
参考:
https://blog.csdn.net/WYA1993/article/details/82799197
https://blog.csdn.net/chengqiuming/article/details/80805667
8,查询字符编码方式
zuul:
forceOriginalQueryStringEncoding: true
HttpServletRequest::getQueryString 用这个方式获取编码方式
RequestContext.getCurrentContext().setRequestQueryParams(someOverriddenParameters)轻松覆盖查询参数,因为查询字符串现在直接在原始的HttpServletRequest上获取。
9,普通嵌入Zuul
10,禁用Zuul过滤器
通过配置规则禁用某个过滤器
例如,禁用org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter设置zuul.SendResponseFilter.post.disable=true
11,为路线提供Hystrix回退
通过zuul实现服务降级
自定义一个回退的类,在类中返回的路由设置你需要降级的路由,用*表示为所有服务提供降级,并设置好返回的内容
这里是路由配置的样子。
zuul:
routes:
customers: /customers/**
class MyFallbackProvider implements ZuulFallbackProvider {
@Override
public String getRoute() {
return "customers"; ----这里配置为*表示为所有的服务设置降级
}
@Override
public ClientHttpResponse fallbackResponse() {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return 200;
}
@Override
public String getStatusText() throws IOException {
return "OK"; ----返回的内容
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("fallback".getBytes()); ----返回的内容
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
}