SpringCloud(四):Gateway网关

编写:HorinJsor


前言

后端的服务调用通过Eurka或者Feigen实现,那么前端调用服务该如何实现呢?这就涉及到了网关


一、网关的主要功能

1、身份认证和权限校验
2、服务路由、负载均衡
3、请求限流

在SpringCloud中网关的实现包括两种:GatewayZuul
本文只介绍Gateway。


二、Gateway搭建步骤

原理

网关原理图


1.引入依赖:创建新的module,引入SpringCloudGateway的依赖和nacos的服务发现依赖:

注意:nacos的作用相当于将Gateway注册成一个服务,目的是注册到注册中心,使用路由负载均衡。不要引入Web依赖,因为他不是tomcat服务器,是net

<!--网关依赖-->
<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.配置动态路由 方式一:在配置文件yaml中编写路由配置及nacos地址

  • routes :路由规则配置,可以是列表。
  • predicates :断言判断,写接口路径。
server:
  port: 80 # 网关端口
spring:
  application:
    name: gateway # 服务名称
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos地址,目的是注册到注册中心,使用路由负载均衡。
    gateway:
      routes: # 网关路由配置
        - id: user-service # 路由id,自定义,只要唯一即可
          # uri: http://127.0.0.1:8081 # 路由的目标地址,静态,固定地址不建议写定。
          uri: lb://userservice # 路由的目标地址(动态):lb就是负载均衡,后面跟服务名称
          predicates: # 路由断言,也就是判断请求是否符合路由规则的条(前端访问路径)
          	# - Path=/user/login 静态,不建议写定
          	- Path=/user/**  #动态
         
        - id: order-service
          uri: lb://orderservice
          predicates:
          	- Path=/order/**

3.配置动态路由 方式二:基于代码的方式路由

创建配置类

@Configuration
public class GatewayConfig {
	@Bean
	public RouteLocator routeLocator(RouteLocatorBuilder routeLocatorBuilder) {
	RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
	routes
		//path_rote_guonei为路由id,usri为路由目标地址,path为断言,符合规则的条。
		.route("path_rote_guonei", r -> r.path("/guonei").uri("http://news.baidu.com/guonei"))
		.route("path_rote_guoji", r -> r.path("/guoji").uri("http://news.baidu.com/guoji"))
		.route("path_rote_tech", r -> r.path("/tech").uri("http://news.baidu.com/tech"))
		.route("path_rote_lady", r -> r.path("/lady").uri("http://news.baidu.com/lady"))
		.build();
	return routes.build();
}

4.动态路由测试:访问

在地址栏输入:

http://localhost:80/user-service/user/login
IP:端口/服务名称/接口路径

如果使用的是静态路由:
http://localhost:80/user/login
IP:端口/接口路径

如果没有引入注册中心,不用写服务名称。


三、Gateway网关:路由断言(判断)工厂

  • 根据规则断言

1.工厂产品示例

1.断言用于判断请求是否符合路由规则的条。
2.是给每一个路由配置的。
3.在动态路由种不会生效
具体例子可查看官方文档: SpringCloud网关路由工厂
在这里插入图片描述

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates: #断言写在此处
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]

四、Gateway网关:路由过滤器

检验前端带来的东西:

  • Token校验
  • 参数校验
  • 黑名单校验

1.工厂过滤器

官方文档:工厂路由过滤器

spring:
  application:
    name: gateway # 服务名称
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos地址
    gateway:
      routes: # 网关路由配置
        - id: order-service
          uri: lb://orderservice
          predicates:
            - Path=/order/**
          filters: # 这里写局部过滤器
            - AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头
      default-filters: # 默认过滤器,会对所有的路由请求都生效
        - AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头

2.全局过滤器GlobalFilter

自定义类,实现GlobalFilter接口,添加@Order注解:

  • @Order注解:过滤器优先级
@Order(-1) //过滤器可以不止一个,进行排序。
@Component
public class AuthorizeFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1.获取请求参数
        MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
        // 2.获取authorization参数
        String auth = params.getFirst("authorization");
        // 3.校验
        if ("admin".equals(auth)) {
            // 放行
            return chain.filter(exchange);
        }
        // 4.拦截
        // 4.1 拦截方式一
        //说明是黑名单里面的 ip
		//ServerHttpResponse response = exchange.getResponse();
		//response.setStatusCode(HttpStatus.UNAUTHORIZED);
		//Map<String, Object> map = new HashMap<>();
		//map.put("code", HttpStatus.UNAUTHORIZED);
		//map.put("msg", "非法访问");
		//response.getHeaders().add("content-Type","application/json;charset=UTF-8");
		//ObjectMapper objectMapper = new ObjectMapper();
		//byte[] bytes = objectMapper.writeValueAsBytes(map);
		//DataBuffer buffer = response.bufferFactory().wrap(bytes);
		//return response.writeWith(Mono.just(buffer));
        
        // 4.2 拦截方式二
        exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
        // 4.3 结束处理
        return exchange.getResponse().setComplete();
    }
}

3.过滤器执行顺序

  • 当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。
  • order值越小,优先级越高。

五、Gateway 结合 redis 实现请求量限流

原理:发限量令牌,有的可以通过访问。

  • 解决IP频繁访问
  • 解决接口请求量大

1.添加依赖

<!--限流要引入 Redis-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

2.创建配置类 RequestRateLimiterConfig

@Configuration
public class RequestRateLimiterConfig {
	/**
	* IP 限流
	* 把用户的 IP 作为限流的 Key
	*
	* @return
	*/
	@Bean 
	@Primary //主候选Bean
	public KeyResolver hostAddrKeyResolver() {
		return (exchange) -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
	}
	
	/**
	* 用户 id 限流
	* 把用户 ID 作为限流的 key
	*
	* @return
	*/
	@Bean
	public KeyResolver userKeyResolver() {
		return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
	}
	
	/**
	* 请求接口限流
	* 把请求的路径作为限流 key
	*
	* @return
	*/

	@Bean
	public KeyResolver apiKeyResolver() {
		return exchange -> Mono.just(exchange.getRequest().getPath().value());
	}
}

3.修改配置文件

server:
	port: 80
spring:
	application:
		name: gateway-80
	cloud:
		gateway:
			enabled: true
			routes:
				- id: user-service
				uri: lb://consumer-user-service
				predicates:
					- Path=/info/**
				filters:
					- name: RequestRateLimiter
					args: #主要是配置这里
						key-resolver: '#{@hostAddrKeyResolver}' #配置类种的方法名称
						redis-rate-limiter.replenishRate: 1
						redis-rate-limiter.burstCapacity: 3
redis: #redis 的配置
	host: 192.168.226.128
	port: 6379
	database: 0
eureka:
	instance:
		instance-id: ${spring.application.name}:${server.port}
		prefer-ip-address: true
	client:
		service-url:
			defaultZone: http://localhost:8761/eureka/

六、跨域问题

网关处理跨域采用的同样是CORS方案,并且只需要简单配置即可实现:

spring:
  cloud:
    gateway:
      # 。。。
      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
        corsConfigurations:
          '[/**]':
            allowedOrigins: # 允许哪些网站的跨域请求 
              - "http://localhost:8090"
              - "http://www.leyou.com"
            allowedMethods: # 允许的跨域ajax的请求方式
              - "GET"
              - "POST"

总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值