一、为什么需要网关(理论)
1.1、gateway和zuul技术的区别
二、搭建网关服务
分析这个localhost:10010/user/1 路径:
三、路由断言工厂
四、网关过滤器
代码演示如下所示:
五、全局过滤器GlobalFlter
代码演示全局过滤器GlobalFlter:
登录拦截:判断用户身份权限
六、过滤器的执行顺序
七、网关的cors跨域配置
解决跨域问题:CORS方案
总结一句话就是:当客户端发送url请求的时候,我们gateway网关会先判断客户端发送的这个url请求是否满足断言规则,如果都满足的话那么就路由到相对应的微服务对应的服务器访问地址当中去,如果不满足断言规则,那么就别想路由了,直接这个客户端发送的url请求就进不来了。
第一步:
第二步:
server:
port: 10010 # 网关默认端口10010
spring:
application:
name: gateway # 服务名称(也可以说是模块名)
cloud:
nacos:
server-addr: localhost:8848 # nacos注册中心地址
gateway:
routes:
- id: user-service # 路由id,这个id自定义可以随便写,只要是唯一的即可
uri: lb://userservice # 路由的目标地址 lb:负载均衡 (也就是说路由到微服务中userservice服务名对应的服务器访问地址中去)
predicates: # 路由断言,判断请求是否符合规则
- Path=/user/** # 当客户端发送的请求是这样的url格式的话,就路由到上面的uri对应的目标地址上
也就是说配置文件中我们知道,我们gateway网关会将客户端发送的url格式为:/user/** 形式的url访问路径路由到服务器名为userservice中的服务器访问地址当中去,然后就可以拿到相对应的微服务的资源数据了:
也就是说客户端通过发送/user/**格式的url请求路径,gateway网关会把这个客户端发送的url路径通过负载均衡的形式路由到userservice服务器名当中,我们上面知道这个userservice服务器名中有两个用户模块功能的服务器访问地址,(也就是说通过这两个服务器访问地址随便一个就可以拿到用户模块功能中的资源数据了),因此路由到用户模块中的服务器访问地址后,就可以通过客户端传递请求的/user/1对用户功能模块发送url请求获取相对应的资源数据了:
总结一句话就是:当客户端发送url请求的时候,我们gateway网关会先判断客户端发送的这个url请求是否满足断言规则,如果都满足的话那么就路由到相对应的微服务对应的服务器访问地址当中去,如果不满足断言规则,那么就别想路由了,直接这个客户端发送的url请求就进不来了。
在springcloud中像这种断言规则有十几种:
具体这些规则在配置文件中该如何使用,直接进下面的文档地址,查看文档根据文档写配置代码即可:Spring Cloud 网关 | 中文文档3.1.1https://docs.gitcode.net/spring/guide/spring-cloud/spring-cloud-gateway.html#_4-%E9%85%8D%E7%BD%AE%E8%B7%AF%E7%94%B1%E8%B0%93%E8%AF%8D%E5%B7%A5%E5%8E%82%E5%92%8C%E7%BD%91%E5%85%B3%E8%BF%87%E6%BB%A4%E5%99%A8%E5%B7%A5%E5%8E%82
具体操作演示如下所示:
总结过滤器: 也就是说客户端的url请求,本来已经通过gateway网关的断言规则了,本来已经可以把这个客户端的url请求路由到我们微服务(比如用户功能模块)的服务器访问地址当中了,本来可以拿到指定路径下的资源数据了,但是就是因为有过滤器的存在,在把客户端的url路由到服务器访问地址的时候,会先被过滤器拦截下来,拦截器也可以做一些操作。
思考:这些过滤器能做哪些工作呢:
上面只展示了5种网关过滤器的作用,具体多少种可以上官网上直接查文档使用即可:
Spring Cloud 网关 | 中文文档3.1.1https://docs.gitcode.net/spring/guide/spring-cloud/spring-cloud-gateway.html#_6-gatewayfilter%E5%B7%A5%E5%8E%82
我们就以给当前客户端发送的url请求添加一个请求头为例进行演示:
代码如下所示:
我们知道这个客户端发送的url请求通过了gateway的断言规则,并且我们网关过滤器也为其url添加了一个请求头的数据。
我们还要知道客户端发送的这个url是到用户功能模块微服务的下面这个功能中的:
补充能量:
: 也就是说当客户端发送url请求通过了gateway网关的断言规则后,本来打算路由到微服务的时候,我们全局过滤器GlobalFlter把客户端发送的url请求路径拦截了下来做了一些判断,看是否让这个客户端发送的url请求访问微服务中的资源数据。
补充能量: 这个Order注解的作用
首先通过下图我们知道,有可能我们会设定很多个全局过滤器,如下所示就可以说设定了三个全局过滤器,但是我们肯定要给这三个全局过滤器一个先后顺序吧,要不然谁知道先执行哪一个全局过滤器啊,因此就通过这个Order注解中的参数值,当值越小的时候,优先级就越高,也就是说当有多个全局过滤器的时候先执行Order注解中参数值最小的那个全局过滤器。
package cn.itcast.gateway;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 定义成全局过滤器的方式: 实现GlobalFilter接口,并且实现filter方法
* (因为这个全局过滤器拦截下来客户端的url请求后,就在这个filter方法中做种种逻辑操作的)
* 注: @Component 这个注解别忘记加
*/
@Order(1) // 这个Order注解的作用就是优先级问题,越小优先级越大
@Component
public class AuthorizeFilter implements GlobalFilter {
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1、获取客户端url路径上的参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap params = request.getQueryParams(); // 路径上的所有参数都会先被这个Map集合管理起来
// 2、获取参数集合中的 authorization 参数
String auth = params.getFirst("authorization");
// 3、判断参数值是否和admin值一致
if ("admin".equals(auth)){
// 4、一致的话就放行,让客户端向微服务发送url请求,拿到相对应的资源数据
return chain.filter(exchange);
}
// 5、不一致的话,就拦截下来(也就是说不让客户端访问资源了,哪来的回哪去吧)
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); // 设置状态码(UNAUTHORIZED对应的是401,我们可以设置个状态码让客户端知道我们给他拦截了,登录失败)
return exchange.getResponse().setComplete(); // 拦截
}
}
然后客户端就可以发送url请求相对应的资源了:
当满足全局过滤器设定的条件时:
首先要先明白什么是跨域:
它是由浏览器的同源策略造成的,同源策略:是指协议,域名,端口都要相同,其中有一个不同都会产生跨域。
http: 协议 www.... 域名 8080 端口
打个比方如下所示:
http://www.123.com/index.html 调用 http://www.123.com/server.php (非跨域)
http://www.123.com/index.html 调用 http://www.456.com/server.php (主域名不同:123/456,跨域)
http://abc.123.com/index.html 调用 http://def.123.com/server.php (子域名不同:abc/def,跨域)
http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.php (端口不同:8080/8081,跨域)
http://www.123.com/index.html 调用 https://www.123.com/server.php (协议不同:http/https,跨域)
请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域
代码演示跨域问题如下所示:
也就是说浏览器:127.0.0.1:8090 调用 ,域名和端口号都不一样,肯定就是跨域了,因此这个浏览器就调用不到这个路径下的资源数据。