在内部调用微服务时我们用feign去调用 而在外部访问时则是直接发送请求调用 其实这存在一个问题 我们的微服务直接摆烂 允许任何人来访问 是不是有点不大安全 你要知道不是所有的业务都是对外公开的 有很多业务是属于公司内部的工作人员或者管理人员才可以去访问 结果现在赤裸裸的摆在这里 允许任何人都可以访问 所以我们得对用户的身份进行验证 如果是我们的工作人员或者内部人员才让访问 否则拦住不让进 做这个事情的 就是Gateway网关 一切请求要先到官网再到微服务
官网功能
- 身份认证和权限校验
- 服务的路由,负载均衡
- 请求限流
官网的技术实现
- gateway
- zuul
这两个我们该选那一个呢?
Zuul是基于servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能 因此目前来讲企业都会选用Gateway做为网关。
搭建网关Gateway
######首先引入SpringCloudGateway的依赖和nacos的服务发现依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
######创建启动类
@SpringBootApplication
public class SCGatewayApp {
public static void main(String[] args) {
SpringApplication.run(SCGatewayApp.class, args);
}
}
编写路由配置以及nacos地址
server:
port: 20001 #网关端口
spring:
application:
name: E-commerce-wms-gateway #服务名称
cloud:
nacos:
server-gateway:localhost:8848 #nacos地址
gateway:
routes: #网关路由配置
- id: auth #路由id,自定义,只要唯一即可
#uri: http://127.0.0.1:8081#路由的目标地址 http就是规定地址 (这种url我们一般不去使用)
uri: lb://E-commerce-wms-uaa #路由的目标i地址lb就是负载均衡,后面跟服务名称 lb就是loadBalancel缩写
predicates: #路由断言,也就是判断请求是否符合路由规则的条件
- Path=/api-uaa/** #这个是按照路径匹配,只要以/api-uaa/开头就符合要求 简单来说就是只要你的请求是api-uaa开头那么我就给你代理到E-commerce-wms-uaa中
filters:
- PreserveHostHeader #为请求添加一个preserveHostHeader=true的属性,路由过滤器会检查该属性以决定是否要发送原始的Host
简单的一张流程图
路由断言工厂Route Predicate Factory
网关路由可以配置的内容包括:
- 路由id:路由唯一标示
- uri:路由目的地,支持lb和http两种
- predicates:路由断言,判断请求是否符合要求,符合则转发到路由目的地
- filters:路由过滤器,处理请求或响应
我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件
Predicate Factory就是断言工厂:会去读取用户定义的断言规则,然后把他解析出来 再去判断
Spring提供了11种基本的Predicate工厂
咱们上述用的就是path
路由过滤器GatewayFilter
GatewayFilter是网关中提供的一种过滤器,可以对进入的网关请求和微服务返回的响应做处理:
请求在过访问微服务时 肯定要进入网关路由 而在路由中则可以配置多个过滤器 形成一个过滤器链
在这个过程中我们可以将他的请求头请求体拿出来加个什么通讯信息什么的都是可以的
spring给我们提供了31多个过滤器感兴趣的可以去spring官网上了解 大多数都是顾名思义的 看名称就知道 而且里面详细介绍了各种过滤器的使用
如果想对所有路由都生效那么可以设置默认路由器default-filter 这个配置因为是全局的所以要和routes同级
全局过滤器GlobalFilter
全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样
区别在于GatewayFilter通过配置定义,处理逻辑是固定的。而GlobalFilter的逻辑需要自己写代码实现
定义方式是实现GlobalFilter接口.
//@Order(0)//过滤器的执行顺序 通过直接 或者Ordered 接口都可以实现数值越小顺序越前 负数比正数前
@Component
public class RequestStatisticsFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//获取请求参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> params = request.getQueryParams();
//获取参数中的aaaa
String first = queryParams.getFirst("aaaa");
//判断参数值是否等于admin
if("admin".equals(first)){
//是放行
return chain.filter(exchange);
}
//否 设置状态码
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
//拦截请求
return exchange.getResponse().setComplete();
}
@Override
public int getOrder() {
return 0;
}
}
过滤器执行顺序
请求进入网关会碰到三类过滤器:当前路由的过滤器,DefaultFilter,GlobaiFilter
请求路由后,会将当前路由过滤器和DefaultFilter,GlobaiFilter合并到一个过滤器链(集合)中,排序依次执行每个过滤器
每一个过滤器都必须指定一个int类型的order指,order指越小,优先级越高,执行顺序越靠前。
GlobaiFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定。
路由过滤器和DefaultFilter的order由spring指定,默认是按照声明顺序从1递增。
当过滤器的order值一样时,会按照defauFilter > 路由过滤器 > GlobaiFilter的顺序执行。
网关跨域
跨域:域名不一致就是跨域,主要包括:
- 域名不同:www.taobao.com和www.taobao.org和www.jd.com和miaosha.jd.com
- 域名相同,端口不同:localhost:8080和localhost:8081
跨域就一定会存在问题吗???
不一定 比如我们user服务调用order服务 不会存在跨域问题
跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求浏览器拦截的问题
我们服务调用服务和浏览器ajax一点关系没有 所以也不存在跨区问题
解决方案:CORS
Gateway其实已经帮我们做好了CORS的底层逻辑了 咱们只需要简单的配置即可实现
spring:
cloud:
gateway:
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true #解决options请求被拦截问题
cors-configurations:
'[/**]':
allowedOrigins:#允许哪些网站的跨域请求
- "http://taobao.com"
- "http://taobao.org"
allowedMethods:#允许的跨域ajax请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*"#允许在请求中携带的头信息
allowCredentials: true#是否允许携带cookie
maxAge: 360000#这次跨域检测的有效期
不要着急,最好的总会在最不经意的时候出现