微服务学习:Gateway服务网关

发布时间:2023年12月17日

一,Gateway服务网关的作用:

  1. 路由请求:Gateway服务网关可以根据请求的URL或其他标识符将请求路由到特定的微服务。

  2. 负载均衡:Gateway服务网关可以通过负载均衡算法分配请求到多个实例中,从而平衡各个微服务的负载压力。

  3. 安全认证:Gateway服务网关可以提供安全认证功能,例如对请求进行身份验证、授权等,保障系统的安全性。

  4. 限流熔断:Gateway服务网关可以对请求进行限流和熔断处理,防止系统因为突发的大量请求而崩溃。

  5. 日志记录:Gateway服务网关可以对请求进行日志记录,方便系统管理员进行监控和调试。

  6. 缓存处理:Gateway服务网关可以对请求进行缓存处理,减少微服务的响应时间和网络延迟。

?二,Gateway服务网关快速使用:

1.创建服务(子模块)

2.导入网关依赖

<!--网关-->
<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>

3.编写启动类

GatewayApplication.java

@SpringBootApplication
public class GatewayApplication {
	public static void main(String[] args) {
		SpringApplication.run(GatewayApplication.class, args);
	}
}

4.创建配置文件application.yml

server:
  port: 10010 # 网关端口
spring:
  application:
    name: gateway # 服务名称
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos地址
    gateway:
      routes: # 网关路由配置
        - id: userservice # 路由id,自定义,只要唯一即可
          # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
          uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
          predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
            - Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
  • server部分定义了网关的端口号为10010,即监听在该端口上接收外部请求。

  • spring部分指定了应用的名称为"gateway",方便在注册中心或其他组件中标识和查找该服务。

  • spring.cloud.nacos部分配置了Nacos注册中心的地址为localhost:8848,用于服务的注册和发现。

  • spring.cloud.gateway.routes部分是网关的路由配置,包括多个路由规则。在这个示例中,只配置了一个路由规则。

    • id字段是路由的唯一标识,可以自定义,用于区分不同的路由。

    • uri字段指定了路由的目标地址。在这个示例中,使用了负载均衡的方式,通过lb://userservice指向名为"userservice"的微服务,其中lb表示负载均衡。

    • predicates字段定义了路由断言,用于判断请求是否符合路由规则的条件。在这个示例中,使用了Path=/user/**作为断言条件,只有请求路径以/user/开头的请求才会匹配到这个路由。

三,网关路由流程?四,断言工厂Route Predicate Factory

名称说明示例
After是某个时间点后的请求- After=2037-01-20T17:42:47.789-07:00[America/Denver]
Before是某个时间点之前的请求- Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai]
Between是某两个时间点之前的请求- Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver]
Cookie请求必须包含某些cookie- Cookie=chocolate, ch.p
Header请求必须包含某些header- Header=X-Request-Id, \d+
Host请求必须是访问某个host(域名)- Host=.somehost.org,.anotherhost.org
Method请求方式必须是指定方式- Method=GET,POST
Path请求路径必须符合指定规则- Path=/red/{segment},/blue/**
Query请求参数必须包含指定参数- Query=name, Jack或者- Query=name
RemoteAddr请求者的ip必须是指定范围- RemoteAddr=192.168.1.1/24
Weight权重处理

四,过滤器工厂?(GatewayFilter )

例如:

名称说明
AddRequestHeader给当前请求添加一个请求头
RemoveRequestHeader移除请求中的一个请求头
AddResponseHeader给响应结果中添加一个响应头
RemoveResponseHeader从响应结果中移除有一个响应头
RequestRateLimiter限制请求的流量

1.请求头过滤器?

spring:
  cloud:
    gateway:
      routes:
      - id: user-service 
        uri: lb://userservice 
        predicates: 
        - Path=/user/** 
        filters: # 过滤器
        - AddRequestHeader=token,itgaohe # 添加请求头

2.默认过滤器(注意:级别高一级)

spring:
  cloud:
    gateway:
      routes:
      - id: user-service 
        uri: lb://userservice 
        predicates: 
        - Path=/user/**
      default-filters: # 默认过滤项
      - AddRequestHeader=token2,itgaohe22 # 添加请求头

3.全局过滤器

全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。区别在于GatewayFilter通过配置定义,处理逻辑是固定的;而GlobalFilter的逻辑需要自己写代码实现。

例如:

定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:

  • 参数中是否有auth,

  • auth参数值是否为admin

如果同时满足则放行,否则拦截(注意通过路由访问)

//1.实现接口GlobalFilter   重写filter
//2.写业务
//3.保证被spring管理
@Component
public class AuthFilter implements GlobalFilter {
    //要求请求参数中有auth=admin
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1.获取请求参数=获取请求参数+获取参数列表
        MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
        // 2.获取auth参数
        String auth = params.getFirst("auth");
        // 3.校验
        if ("admin".equals(auth)) {
            // 放行
            return chain.filter(exchange);
        }
        // 4.拦截
        System.out.println("您未登录请登录");
        // 4.1.禁止访问,设置状态码
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        // 4.2.结束处理
        return exchange.getResponse().setComplete();
    }
}

运行后错误显示? 注意后面携带(?auth=admin)就成功了

4.网关顺序?

排序的规则是什么呢?

  • 每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前

  • GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,可以指定-1

  • 路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。

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

五,跨域问题&同源问题

协议+域名+端口号 三者相同才是同源的

报错类型?

Access to XMLHttpRequest at 'http://example.com/api/data' from
 origin 'http://yourdomain.com' has been blocked by CORS policy:
 No 'Access-Control-Allow-Origin' header is present on the requested resource.

解决方法

spring:
  cloud:
    gateway:
      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
        corsConfigurations:
          '[/**]': #所有路径都生效
            allowedOrigins: # 允许哪些网站的跨域请求 
              - "http://localhost:8090"
              - "null"
            allowedMethods: # 允许的跨域ajax的请求方式
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允许在请求中携带的头信息,*代表任意
            allowCredentials: true # 是否允许携带cookie
            maxAge: 360000 # 这次跨域检测的有效期

六,问题总结

springbooot文件执行顺序:

项目外配置文件(nacos配置文件)>aplication-dev.properties >application.properties?
aplication.yaml >aplication.yml>bootstrap.yaml

bootstrap.yaml最后生效的原因:

bootstrap.yml 由父Spring ApplicationContext加载,承接上下文。
bootstrap.yml 可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。
Spring Boot 在加载配置文件时,会按照特定的顺序进行加载和覆盖。当存在多个配置文件时,后加载的文件会覆盖先加载的文件中相同配置项的值。

bootstrap.yaml 可以实现热部署或云配置

热部署配置文件的生效顺序是:

云userserver-dev.yaml > 云userserver.yaml > 本地application.yaml

热部署同步实现方式有几种:

@RefreshScope:在 Spring Boot 应用程序中使用它可以实现动态更新配置信息。如果在运行时更改了配置信息,可以使用 @RefreshScope 注解来告诉 Spring Boot 重新加载配置信息。

@ConfigurationProperties(prefix = "pattern"):是 Spring Boot 中一种用于绑定配置文件中属性值到 Java 对象的方式。其中,prefix 参数指定了在配置文件中要绑定的属性的前缀,这样可以避免在 Java 类中重复书写相同的前缀。在 application.properties 配置文件中配置pattern的属性。

例如,在 application.properties 配置文件中,可能会有以下属性:

pattern.enabled=true 
pattern.timeout=1000 
pattern.retry-count=3

我们可以定义一个 Java 类,使用 @ConfigurationProperties(prefix = "pattern") 注解来将这些属性值绑定到类中的属性上:

@Configuration 
@ConfigurationProperties(prefix = "pattern") 
public class PatternProperties { 
    private boolean enabled; 
    private int timeout;
    private int retryCount; 
// getters and setters 
}

为什么要用feign?& restTemplete的缺点

restTemplete( 1. 侵入式开发(开发过程中需要强制性地修改现有代码或使用特定的框架、技术等,从而使得应用程序与特定技术或框架耦合度较高的开发方式。这种开发方式会导致代码的可维护性和可扩展性变差,增加了系统的维护成本,同时也限制了开发人员的选择。) 2. 配置复杂 3.优化不方便 )

feign好处:

好处:

1. 代码解耦

2. 自定义配置

3. 连接池调优

4. 他可以和spring其他框架无缝衔接

5.学习成本很低(springmvc接口规范)

feign的使用

  1. Feign 请求响应格式配置:在使用 Feign 进行服务间调用时,可以通过 Feign 的配置来设置请求和响应的格式。例如,你可以使用 @RequestMapping 注解的 produces 属性来指定接受的媒体类型,也可以使用 @RequestMapping 注解的 consumes 属性来指定发送的媒体类型。

    @FeignClient(name = "example", 
    url = "${example.url}",
    configuration = MyFeignConfiguration.class)
    public interface ExampleFeignClient {
        @RequestMapping
    (value = "/resource",
     method = RequestMethod.GET,
     produces = "application/json")
        String getResource();
    }
    
  2. Feign 缓存支持:你可以使用 Spring 的缓存框架(如 Spring Cache)来为 Feign 接口添加缓存支持。首先需要在配置类上加上 @EnableCaching 注解,然后在需要缓存的方法上添加 @Cacheable 注解。

    @Service
    public class MyService {
        @Cacheable("resourceCache")
        public String getResource() {
            // ...
        }
    }
    
  3. Spring @RefreshScope 支持:在 Spring Cloud Config 中,你可以使用 @RefreshScope 注解来实现配置的动态刷新。在需要动态刷新的 Bean 上添加 @RefreshScope 注解,然后在应用启动时,通过 Actuator 的 /actuator/refresh 端点来触发配置的刷新。

    @RestController
    @RefreshScope
    public class MyController {
        @Value("${my.property}")
        private String property;
    
        @GetMapping("/property")
        public String getProperty() {
            return property;
        }
    }
    
  4. Feign 支持 OAuth2:在使用 Feign 进行服务间调用时,可以集成 OAuth2 来进行安全的认证和授权。你可以在 Feign 客户端的请求头中添加 OAuth2 的认证信息,以此来实现对受保护资源的访问。

    @FeignClient(name = "oauth2-service",
     configuration = OAuth2FeignClientConfiguration.class)
    public interface OAuth2FeignClient {
        @RequestLine("GET /resource")
        @Headers("Authorization: Bearer {token}")
        String getResource(@Param("token") String token);
    }
    

feign的优化

日志级别设置为 basic:在使用 Feign 进行服务调用时,可以通过配置来设置 Feign 的日志级别。将日志级别设置为 basic 可以输出基本的请求和响应信息。?

logging:
  level:
    com.netflix.feign: basic

使用 HttpClient 或 OKHttp 代替 URLConnection:可以使用 Feign 的 HttpClient 支持来替代默认的 URLConnection,或者使用 OKHttp 作为底层的 HTTP 客户端。

HttpClient:

依赖:

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

配置文件:

feign.httpclient.enabled=true
feign.httpclient.maxConnections=200
feign.httpclient.maxConnectionsPerRoute=20

OKHttp:

依赖:

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
</dependency>

配置文件:

feign.okhttp.enabled=true

网关重要概念:

断言:用于定义匹配请求的条件。当客户端发起请求时,网关会根据配置的断言条件来决定是否将请求路由到特定的微服务或后端。

过滤器:(默认的 路由 全局 每一个过滤器都必须指定一个int类型的order值,**order值越小,优先级越高,执行顺序越靠前**。GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定。路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。

跨域访问

跨域:域名不同&域名相同、端口不同

浏览器不限制的:<script> <link> <img>等

限制 AJAX 请求的跨域访问的处理:可以在服务端设置响应头中的 Access-Control-Allow-Origin 属性,指定允许跨域访问的源。如果请求的来源不在允许的列表中,则浏览器会拦截这个跨域请求。

Access-Control-Allow-Origin: http://www.example.com

gateway如何跨域:

在配置文件中添加跨域过滤器的配置

spring:
  cloud:
    gateway:
      default-filters:
        - name: Cors
          args:
            allowedOrigins: "http://www.example.com"
            allowedMethods: "POST, GET, PUT, OPTIONS, DELETE, PATCH"
            allowedHeaders: "Content-Type, Authorization"
            allowCredentials: true

在跨域过滤器中添加 Access-Control-Allow-Origin 属性

@Bean
public CorsGatewayFilterFactory corsGatewayFilterFactory() {
    CorsGatewayFilterFactory factory = new CorsGatewayFilterFactory();
    factory.setAllowedOrigins("http://www.example.com");
    return factory;
}

文章来源:https://blog.csdn.net/A2029292473/article/details/134982020
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。