GateWay网关笔记
1. Gateway网关简介
为微服务架构提供一种简单有效的统一的 API 路由管理方式。
API网关
API 网关是一个处于应用程序或服务(提供 REST API 接口服务)之前的系统
- 管理授权
- 访问控制
- 流量限制
REST API 接口服务就被 API 网关保护起来,对所有的调用者透明
隐藏在 API 网关后面的业务系统就可以专注于创建和管理服务,而不用去处理这些策略性的基础设施。
职能
- 请求接入
- 作为所有API接口服务请求的接入点
- 业务聚合
- 作为所有后端业务服务的聚合点
- 中介策略
- 实现安全、验证、路由、过滤、流量控制等策略
- 统一管理
- 对所有API服务和策略进行统一的管理
为什么需要网关
- 身份认证和权限验证
- 服务路由、负载均衡
- 请求限流
在SpringCloud中网关的实现包括两种:
- gateway
- zuul
Gateway 可以看做是一个 Zuul 1.x 的升级版和代替品,比 Zuul 2 更早的使用 Netty 实现异步 IO。
从而实现了一个简单、比 Zuul 1.x 更高效的、与 Spring Cloud 紧密配合的 API 网关。
GateWay的几个重要概念:
- Route(路由):网关的基本构建块。
- 组成:
- 一个ID
- 一个目标URI
- 一组断言
- 一组过滤器定义
- 如果断言为真,则路由匹配
- 组成:
- Predicate(断言):输入类型是一个ServerWebExcahnge。
- 可用来匹配来自HTTP请求的任何内容,例如headers或参数
- 过滤器(filter)
- GateWay中的Filter分为两种类型的filter:
- GateWay Filter
- Global Filter
- 过滤器Filter将会对请求和响应进行修改处理
- GateWay中的Filter分为两种类型的filter:
2. GateWay入门
本步骤如下:
1.创建SpringBoot工程gateway,引入网关依赖
<!--网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos服务发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2. 编写启动类
package com.example.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient //Nacos注册
public class GateWayApplication {
public static void main(String[] args) {
SpringApplication.run(GateWayApplication.class,args);
}
}
3. 编写基础配置和路由规则
server:
port: 10010 # 网关端口
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 网关路由配置
- id: user-service # 路由id,自定义,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求 routes: # 网关路由配置
- id: order-service # 路由id,自定义,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
uri: lb://orderservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/order/** # 这个是按照路径匹配,只要以/user/开头就符合要求
4. 启动网关服务进行测试
启动nacos、启动user-service 同时注入到nacos中
在http://localhost:10010/user/1中即可访问user-service
3. GateWat路由断言工厂
名称 | 说明 | 示例 |
---|---|---|
After | 是某个时问点后的请求 | - After=2037-01-20T17:42:47.789-07:0O[America/Denver] |
Before | 是某个时问点之前的请求 | - Before=2031-04-13T15:14:47.433+08:0O[Asia/Shanghai] |
Between | 是某两个时间点之前的请求 | -Between=2037-01-20T17:42:47.789-07:0O[America/Denver]. 2037-01-21T17:42:47.789-07:0o[America/Denver] |
Cookie | 请求必须包含某些cookie | - Cookie=chocolate,ch.p |
Header | 请求必须包含某些header | - Header=x-Request-ld,ld+ |
Host | 请求必须是访问某个host(域名) | - Host=+.somehost.org.t.anotherhost.org |
Method | 请求方式必须是指定方式 | -Method=GET,POS1 |
Path | 请求路径必须符合指定规则 | - Path-/red/{segment}./blue/*- |
Query | 请求参数必须包含指定参数 | - Query=name, Jack或者-Query=name |
RemoteAddr | 请求者的ip必须是指定范围 | - RemoteAddr=192.168.1.1/24 |
Weight | 权重处理 |
4. 路由的过滤器配置
GateWayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理
- 请求
- 响应
Spring提供了30+的路由过滤工厂
详见:
https://www.springcloud.cc/spring-cloud-greenwich.html#_gatewayfilter_factories
示例:给所有进入userservice的请求添加一个请求头
给所有进入userservice的请求添加一个请求头:Truth=itcast is freaking asewome!
实现方式:
在gateway中修改application.yml文件,给userservice的路由添加过滤器:
server:
port: 10010 # 网关端口
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 网关路由配置
- id: user-service # 路由id,自定义,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求 routes: # 网关路由配置
filters:
- AddRequestHeader=Truth, Itcast is freaking amesome! #添加请求头
- id: order-service # 路由id,自定义,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
uri: lb://orderservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/order/** # 这个是按照路径匹配,只要以/user/开头就符合要求
这个配置则是:
server:
port: 10010 # 网关端口
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 网关路由配置
- id: user-service # 路由id,自定义,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求 routes: # 网关路由配置
filters:
- AddRequestHeader=Truth, Itcast is freaking amesome! #添加请求头
- id: order-service # 路由id,自定义,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
uri: lb://orderservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/order/** # 这个是按照路径匹配,只要以/user/开头就符合要求
default-filters:
- AddRequestHeader=Truth, Itcast is freaking amesome! #添加请求头
5. Globalfilter全局过滤器
全局过滤器的作用也是处理一切进入网关的请求和微服务响应,于GateWayFilter的作用一样
区别在于GateWayFilter通过配置定义,处理逻辑是固定的
而GlobalFilter的逻辑需要自己写代码实现
实现GlobalFilter的接口
exchange: 请求上下文,里面可以获取Request、Response等信息
chain 用来把请求委托给下一个过滤器
定义一个过滤器:
package com.example.gateway;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
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;
@Component
//@Order(-1) //顺序注解 或接Ordered接口
public class AuthorizeFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
/*
* 1. 获取请求参数*/
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> queryParams = request.getQueryParams();
// 2. 获取参数中的authorization参数\
String authorization = queryParams.getFirst("authorization");
// 3. 判断参数值是否等于admin
if("admin".equals(authorization)){
// 4. 是则放行,从过滤器链里找下一个
Mono<Void> filter = chain.filter(exchange);
return filter;
}
// 5. 否则拦截、设置状态码
else{
exchange.getResponse().setStatusCode(HttpStatus.valueOf(401));
return exchange.getResponse().setComplete();
}
}
@Override
public int getOrder() {
return 0;
}
}
6. 跨域问题
什么是跨域问题
跨域:域名不一致就是跨域,主要包括:
域名不同: www.taobao.com 和 www.taobao.org
域名相同,端口不同:localhost:8080和localhost8081
跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
解决跨域问题
在gateway服务的application.yml文件中,添加下面的配置:
spring:
cloud:
gateway:
# 。。。
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]':
allowedOrigins: # 允许哪些网站的跨域请求
- "http://localhost:8090"
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期