微服务分为多个服务,有很多服务是内部人员要用的,但是现在谁都可以访问到,那我们该怎么办呢?
Spring Cloud最新面试题
Spring Cloud Nacos详解之注册中心
Spring Cloud Nacos详解之配置中心
Spring Cloud Nacos详解之集群配置
Spring Cloud Eureka详解
Spring Cloud Frign详解
Spring Cloud Ribbon详解
Spring Cloud Hystrix详解
Gateway
响应式编程,具有更好的性能。
Zuul
阻塞式编程。
1.创建一个新的服务
2.添加网关依赖和nacos服务发现依赖
<!--nacos服务注册发现依赖-->
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
<!--网关gateway依赖-->
org.springframework.cloud
spring-cloud-starter-gateway
3.编写yml配置文件
server:
port: 10086 #端口号
spring:
application:
name: gateway #服务名称
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes:
- id: user-service # 路由id,必须唯一。 用户服务
uri: lb://userservice # 路由的目标地址,lb是负载均衡。
# uri: http://127.0.0.1/user/1 也可以使用这种,但是这种就固定了路由地址,就不能负载均衡了。
predicates: # 路由断言,判断请求是否符合规则,符合就转发到目的路由。可以配置多个规则
- Path=/user/** # 路径断言,判断路径是否是以/user开头,如果是则符合。
- id: order-service # 订单服务
uri: lb://orderservice
predicates:
- Path=/order/**
官网示例
属性 | 描述 | 示例 |
---|---|---|
After | 是某个时间点之后的请求 | -After=2023-01-01T17:42:47.789-07:00[America/Denver] (必须在2023年1月1日17点42分47秒之后发的请求才能通过,根据美国丹佛[America/Denver]的时间算) |
Before | 是某个时间点之前的请求 | -Before=2022-02-22T22:22:22.433+8:00[Asia/Shanghai] (必须在2022年2月22日22时22分22秒之前发的请求才能通过,根据[Asia/Shanghai]上海时间算) |
Between | 是某两个时间点之前的请求 | -Between=时间[时区],时间[时区] |
Cookie | 请求必须包含某些cookie | - Cookie=ikun, rap |
Header | 请求必须包含某些header | - Header=X-Request-Id,\d+ |
Host | 请求必须是访问某个host(域名) | - Host=**.kunkun,**com.cn |
Method | 请求方式必须是指定方式 | -Method=GETPOST |
Path | 请求路径必须符合指定规则 | -path=user/** |
Query | 请求参数必须包含指定参数 | Query=ikun |
RemoteAddr | 请求者的ip必须是指定范围 | - RemoteAddr=192.168.1.1/24 |
Weight | 权重处理 |
对进入网关的请求和微服务返回的响应做处理。比如:添加请求头。
官网示例
1.配置网关服务yml文件
路由过滤器:对当前路由生效。
server:
port: 10086 #端口号
spring:
application:
name: gateway #服务名称
cloud:
gateway:
routes:
- id: user-service # 路由id,必须唯一。 用户服务
uri: lb://userservice # 路由的目标地址,lb是负载均衡。
# uri: http://127.0.0.1/user/1 也可以使用这种,但是这种就固定了路由地址,就不能负载均衡了。
predicates: # 路由断言,判断请求是否符合规则,符合就转发到目的路由。可以配置多个规则
- Path=/user/** # 路径断言,判断路径是否是以/user开头,如果是则符合。
filters:
- AddRequestHeader=Ikun,ji ni tai mei! # 添加请求头,针对某个服务生效。
2.在添加请求头的服务编写代码
在用户服务的controller里面写
/**
* @param id 用户id
* @return 用户
*/
@GetMapping("/{id}")
public User queryById(@PathVariable("id") Long id,
@RequestHeader(value = "Ikun", required = false) String ikun) {
System.out.println("Ikun最喜欢的歌是什么:" + ikun);
return userService.queryById(id);
}
然后访问 localhost:10086/user/1
,控制台就会打印 ikun 的值。
DefaultFilter:对所有路由都生效。
server:
port: 10086 #端口号
spring:
application:
name: gateway #服务名称
cloud:
gateway:
routes:
- id: user-service # 路由id,必须唯一。 用户服务
uri: lb://userservice # 路由的目标地址,lb是负载均衡。
# uri: http://127.0.0.1/user/1 也可以使用这种,但是这种就固定了路由地址,就不能负载均衡了。
predicates: # 路由断言,判断请求是否符合规则,符合就转发到目的路由。可以配置多个规则
- Path=/user/** # 路径断言,判断路径是否是以/user开头,如果是则符合。
default-filters:
- AddRequestHeader=Ikun,ji ni tai mei! #添加请求头,全局生效
对进入网关的请求和微服务返回的响应做处理。和GatewayFilter作用一样
因为GatewayFilter是基于配置实现,处理的逻辑是固定的,GlobalFilter基于代码逻辑实现,更加灵活一些,可以用于验证用户身份等功能。
1.实现GlobalFilter接口
验证身份信息,根据authorization的值是否是ikun
// @Order(-1) 注解方式实现,如果有多个过滤器,越小越早走。
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1.获取请求参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> params = request.getQueryParams();
// 2.获取参数中的 authorization 参数
String auth = params.getFirst("authorization");
// 3.判断参数值是否等于 ikun
if ("ikun".equals(auth)) {
// 4.是,放行
return chain.filter(exchange);
}
// 5.否,拦截
// 5.1.设置状态码,未登录
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// 5.2.拦截请求
return exchange.getResponse().setComplete();
}
/**
* 代码方式实现,实现 Ordered 接口,多个过滤器,返回值越小,越早走。
**/
@Override
public int getOrder() {
return -1;
}
}
2.验证身份
(1) 如果authorization 参数不等于ikun或没有都会报错。
(2) authorization 参数等于 ikun正常访问。
请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤链(集合)中,排序后依次执行每个过滤器**(DefaultFilter -> 路由过滤器 -> GlobalFilter)**。
1.为什么不是同一个过滤器可以放在一个过滤链中呢?由下面可得这三个过滤器本质上都是GatewayFilter
DefaultFilter 和 路由过滤器的实现都是 AddRequestHeaderGatewayFilterFactory
类,最后会生成一个真正的过滤器(GatewayFilter
)。
GlobalFilter的实现是通过 GatewayFilterAdapter
适配器类实现了GatewayFilter
,然后就可以把GlobalFilter适配成GatewayFilter
。
2.路由过滤器和DefaultFilter怎么设置@Order顺序呢?
由spring指定order,按声明顺序1开始递增。
扩展:
跨域: 浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题。
解决: 采用CORS方案,网关处理跨域采用的同样是CORS方案。(简单来说就是浏览器询问服务端让不让这个请求跨域,如果让会返回结果)。
在yml文件配置以下内容
spring:
cloud:
gateway:
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题(浏览器去询问服务端的请求就是options)
corsConfigurations:
'[/**]':
allowedOrigins: # 允许哪些网站的跨域请求
-"http://localhost:8888"
-"http://www.ikun.com"
allowedMethods: # 允许的跨域ajax的请求方式
-"GET"
-"POST"
-"DELETE"
-"PUT"
-"OPTIONS"
allowedHeaders: "*" # 允许请求头跨域
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期