网关gateway
含义与作用
在Java微服务开发中,gateway网关是一个用来处理客户端请求和微服务之间通信的中间层。它常常被用作微服务架构的入口点,负责将外部的请求路由到不同的微服务上。
gateway网关的主要用处包括以下几个方面:
-
路由转发:gateway网关可以根据请求的URL路径、请求方法、请求头等信息,将请求动态地路由到对应的微服务上。通过路由规则的配置,可以实现请求的负载均衡和故障转移,提高系统的可用性和稳定性。
-
服务聚合:在微服务架构中,一个页面可能需要调用多个微服务才能完成。gateway网关可以聚合多个微服务的接口,组合成一个统一的API,对外提供服务。这样,客户端只需请求一次gateway网关的接口,而无需直接调用多个微服务接口,简化了客户端的请求过程。
-
安全控制:gateway网关可以集中处理安全认证和授权,对请求进行身份验证、权限校验等操作。它可以维护用户会话、生成和验证Token,确保只有授权的请求才能访问微服务。
-
限流和熔断:gateway网关可以通过限制每个微服务的请求频率、并发数等方式,对请求进行限流。同时,它也可以实现熔断机制,当某个微服务发生故障或超时时,自动拦截请求,避免对整个系统造成雪崩效应。
-
日志和监控:gateway网关可以集中收集请求日志,记录请求的详细信息,便于后续的审计和故障排查。同时,它也可以对请求进行监控和统计,提供实时的性能指标和错误报警。
总结:gateway网关在Java微服务开发中扮演着重要的角色,它能够为微服务提供路由转发、服务聚合、安全控制、限流和熔断、日志和监控等功能,提高系统的可用性、性能和安全性。
使用
(1)在kaihe-leadnews-gateway(管理所有网关的微服务)导入以下依赖
pom文件
xml
<dependencies>
<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>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
</dependencies>
(2)在kaihe-leadnews-gateway下创建kaihe-leadnews-app-gateway微服务(子网关,某一大块业务的网关,如app端的网关)
引导类:
java
//就是将这个maven项目改成springboot项目,如果新建的kaihe-leadnews-app-gateway项目就是springboot项目,这一块引导类就不用添加,只需添加下面的配置就行了
package com.heima.app.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient //开启注册中心
public class AppGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(AppGatewayApplication.class,args);
}
}
bootstrap.yml
yaml
server:
port: 51601
spring:
application:
name: leadnews-app-gateway
cloud:
nacos:
discovery:
server-addr: 192.168.200.130:8848
config:
server-addr: 192.168.200.130:8848
file-extension: yml
在nacos的配置中心创建dataid为leadnews-app-gateway的yml配置
如下图所示:
yaml
spring:
cloud:
gateway:
globalcors: # 过滤请求的配置
add-to-simple-url-handler-mapping: true # 将该gateway网关添加到Spring MVC中的URL处理映射中
corsConfigurations:
'[/**]': # 匹配所有请求
allowedHeaders: "*" # 允许所有请求头的请求
allowedOrigins: "*" # 跨域处理,允许所有的域
allowedMethods: # 允许的请求方法
- GET
- POST
- DELETE
- PUT
- OPTION
routes: # 路由请求的配置
# 平台管理
- id: user # 路由规则的唯一标识符
uri: lb://leadnews-user # 路由请求的目标地址,表示负载均衡请求到名为 leadnews-user 的微服务
predicates: # 匹配请求的条件
- Path=/user/** # 表示只有请求路径以 /user/ 开头的请求才会被路由到该微服务。
filters: # 在路由过程中对请求进行过滤处理的操作
- StripPrefix= 1 # 表示过滤掉请求路径的前缀 /user/,以便目标微服务能够正确处理请求
# 总结起来,上述路由的这段配置的作用是将以 /user/ 开头的请求路由到名为 leadnews-user 的微服务,并且去除请求路径中的前缀 /user/
环境搭建完成以后,启动项目网关和用户两个服务,使用postman进行测试
请求地址:http://localhost:51601/user/api/v1/login/login_auth
这里要注意,请求路径中IP端口后后面加了个user,而登录的controller和接口上是没有定义user的,就是因为加了gateway网关的路由请求的配置predicates:- Path=/user/**,所以要加上前缀/user/才会被路由到leadnews-user这个微服务,但通过网关之后,因为加了filters: - StripPrefix=1这个配置,请求路径中的/user/前缀就会被去掉,就变成了http://localhost:51601/api/v1/login/login_auth,所以能够访问到leadnews-user上的登录接口。
gateway路由请求就完成了,可以启动项目网关和用户两个服务,用postman访问http://localhost:51601/user/api/v1/login/login_auth来测试登录接口了。
1.3 全局过滤器实现jwt校验
思路分析:
- 用户进入网关开始登陆,网关过滤器进行判断,如果是登录,则路由到后台管理微服务进行登录
- 用户登录成功,后台管理微服务签发JWT TOKEN信息返回给用户
- 用户再次进入网关开始访问,网关过滤器接收用户携带的TOKEN
- 网关过滤器解析TOKEN ,判断是否有权限,如果有,则放行,如果没有则返回未认证错误
具体实现:
第一:
在认证过滤器中需要用到jwt的解析,所以需要把工具类AppJwtUtil拷贝一份到网关微服务
第二:
在网关微服务中新建全局过滤器:
java
package com.kaihe.app.gateway.filter;
import com.kaihe.app.gateway.util.AppJwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
@Slf4j
public class AuthorizeFilter implements Ordered, GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1.获取request和response对象
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
//2.判断是否是登录
if(request.getURI().getPath().contains("/login")){
//放行
return chain.filter(exchange);
}
//3.获取token
String token = request.getHeaders().getFirst("token");
//4.判断token是否存在
if(StringUtils.isBlank(token)){
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
//5.判断token是否有效
try {
Claims claimsBody = AppJwtUtil.getClaimsBody(token);
//是否是过期
int result = AppJwtUtil.verifyToken(claimsBody);
if(result == 1 || result == 2){
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
}catch (Exception e){
e.printStackTrace();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
//6.放行
return chain.filter(exchange);
}
/**
* 过滤器的优先级设置,值越小,优先级越高
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
测试:
启动user服务,继续访问其他微服务,会提示需要认证才能访问,这个时候需要在heads中设置设置token才能正常访问。