logo头像

分享技术,品味人生

微服务-配置中心、feign框架、gw网关

Day.02- 配置中心、Feign声明http框架、GW网关

本章小结:

  1. Nacos 单机、windows集群、linux集群安装
  2. Nacos配置中心的配置和使用,优先级对比
  3. Feign简单使用、日志优化、连接池优化
  4. Feign、boot、api最佳实践
  5. GW网关安装配置、路由断言、三种过滤器实践

未解之谜:

  • ==多环境的分配需要好好琢磨下==
  • 频繁更新的规范?
  • 多环境分区存储

[TOC]


No.01-Nacos配置中心、多集群

1、配置中心

1.1、服务端配置

服务端主要存放频繁热更新的关键配置

  • Data ID采用【服务名-环境.yaml】
  • 配置格式采用YAML
  • 配置内容:以==频繁修改需热更新==的为主

image-20211013112330047

1.2、客户端配置

  • pom依赖

    <!-- nacos配置依赖 -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
    
  • boostrap.yml 启动配置

    spring:
      application:
        name: userservice  #必要元素:服务名称,调取远程配置用
      profiles:
        active: dev #必要元素:环境配置
      cloud:
        nacos:
          server-addr: localhost:8848 # nacos settings
          config:
            file-extension: yaml  # 配置类型
    
  • application配置清理(去除重复项,==分区存储后续再琢磨如何实现==)

    ```yaml
    server:
    port: 8081
    spring:
    datasource:
    url: jdbc:mysql://192.168.20.164:3306/cloud_user?useSSL=false
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver

cloud: # nacos settings

nacos:

discovery:

cluster-name: HZ

mybatis:
type-aliases-package: com.iyyxx.user.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
com.iyyxx: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS




- 配置拉取:webController测试

```java
package com.iyyxx.user.web;

import com.iyyxx.user.config.PatternProperties;
import com.iyyxx.user.pojo.User;
import com.iyyxx.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @Value("${pattern.dateformat}")
    private String dateformat;

    @GetMapping("now")
    public String now() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
    }

}

1.3、配置热更新

  • 方案一,@Value和@RefreshScope搭配使用,不推荐
@Slf4j
@RestController
@RequestMapping("/user")
@RefreshScope	//热更新,配合@Value注解使用
public class UserController {
   
    @Autowired
    private UserService userService;

    @Value("${pattern.dateformat}")
    private String dateformat;

    @GetMapping("now")
    public String now() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
    }

}
  • 方案二,采用@ConfigurationProperties, 推荐

    • @ConfigurationProperties

      package com.iyyxx.user.config;
      
      import lombok.Data;
      import org.springframework.boot.context.properties.ConfigurationProperties;
      import org.springframework.stereotype.Component;
      
      @Data
      @Component
      @ConfigurationProperties(prefix = "pattern")
      public class PatternProperties {
          private String dateformat;
      }
      
    • package com.iyyxx.user.web;
      
      import com.iyyxx.user.config.PatternProperties;
      import com.iyyxx.user.pojo.User;
      import com.iyyxx.user.service.UserService;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.cloud.context.config.annotation.RefreshScope;
      import org.springframework.web.bind.annotation.*;
      
      import java.time.LocalDateTime;
      import java.time.format.DateTimeFormatter;
      
      @Slf4j
      @RestController
      @RequestMapping("/user")
      public class UserController {
      
          @Autowired
          private UserService userService;
      
          @Autowired
          private PatternProperties properties;
      
          @GetMapping("now")
          public String now() {
              return LocalDateTime.now().format(DateTimeFormatter.ofPattern(properties.getDateformat())); //从properties热同步
          }
      
      }
      

1.4、多环境部署

配置可重叠,环境优先级: 服务名-profile.yaml > 服务名.yaml > application.yml(local)

  • 测试准备

    • nacos:userservice.yaml

      • envSharedValue: 服务端共享配置	#仅一份,无重叠覆盖,均可用
        name1: name@服务端共享 #优先级2,如果有更高级配置则被覆盖
        name2: name@服务端共享 #优先级2,覆盖本地
        

        image-20211013120635056

    • nacos:userservice-dev.yaml

      • name1: name1@测试环境专用 #优先级1,覆盖全部
        

        image-20211013120621056

    • 本地:application.yml

      • name1: name@local #优先级3,可被服务端2份覆盖
        name2: name2@local #优先级3,如仅存这份,则显示
        name3: name3@local #优先级3,如仅存这份,则显示
        

    image-20211013120652661

    • 程序配置

      • 补充idea多环境在启动器上的配置,==可不修改yaml文件调整环境配置!==

      image-20211013121057380

      • package com.iyyxx.user.config;
        
        import lombok.Data;
        import org.springframework.boot.context.properties.ConfigurationProperties;
        import org.springframework.stereotype.Component;
        
        @Data
        @Component
        @ConfigurationProperties(prefix = "pattern")
        public class PatternProperties {
            private String dateformat;
            private String envSharedValue;
            private String name1;
            private String name2;
            private String name3;
        }
        
      • package com.iyyxx.user.web;
        
        import com.iyyxx.user.config.PatternProperties;
        import com.iyyxx.user.pojo.User;
        import com.iyyxx.user.service.UserService;
        import lombok.extern.slf4j.Slf4j;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.beans.factory.annotation.Value;
        import org.springframework.cloud.context.config.annotation.RefreshScope;
        import org.springframework.web.bind.annotation.*;
        
        import java.time.LocalDateTime;
        import java.time.format.DateTimeFormatter;
        
        @Slf4j
        @RestController
        @RequestMapping("/user")
        public class UserController {
        
            @Autowired
            private UserService userService;
        
            @Autowired
            private PatternProperties properties;
        
            @GetMapping("prop")
            public PatternProperties properties() {
                return properties;
            }
        }
        
      • 启动dev和test环境并测试

      image-20211013120716928

image-20211013120937473

2、集群搭建

2.1、环境准备

服务 IP 端口 说明
nacos1 127.0.0.1 8841 实际服务端口,未来建议放linux、不同机器保障安全
nacos2 127.0.0.1 8842 实际服务端口,未来建议放linux、不同机器保障安全
nacos3 127.0.0.1 8843 实际服务端口,未来建议放linux、不同机器保障安全
nginx 127.0.0.1 80 反向代理端口,未来建议放linux

2.2、nacos#application.properties 配置(服务端口、db)

### Default web server port:
server.port=8841

#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
spring.datasource.platform=mysql

### Count of DB:
db.num=1

### Connect URL of DB:
db.url.0=jdbc:mysql://192.168.20.164:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=123456

2.3、nacos#cluster.conf 集群清单(IP、端口)

127.0.0.1:8841
127.0.0.1.8842
127.0.0.1.8843

2.4、nginx#nginx.conf配置(反向代理)

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;


    # nacos集群、反向代理配置
    upstream nacos-cluster {
        server 127.0.0.1:8841;
        server 127.0.0.1:8842;
        server 127.0.0.1:8843;
    }

    server {
        listen       80;
        #server_name 采用hosts文件nacos自动生成的? 省的用localhost老报错,生产建议用稳定的域名为后迁移做平滑准备
        server_name  windows10.microdone.cn; 

        location /nacos {
        proxy_pass http://nacos-cluster;
        }
    }

}

2.5、 windows terminal安装及nginx 操作命令

github 下载安装【Windows terminal here

image-20211013152547414

建议设置多窗口、cmd shell

image-20211013152619898

# nacos启动, 进入nagos/bin目录
startup.cmd

# nginx 启动, 进入nginx目录
start nginx

# nginx 关闭
nginx -s stop

# nginx 刷新配置
nginx -s reload

# windows shelle 根据执行文件名查进程
tasklist | findstr nginx

# windows shell 根据文件名杀进程, 支持通配符
taskkill /f /t /im nginx.exe

# windows shell 查询端口占用
netstat -ano|findstr ":80"

2.6、bootstrap.yml 配置修改

spring:
  application:
    name: userservice
  profiles:
    active: dev
  cloud:
    nacos:
      server-addr: windows10.microdone.cn:80  # 端口必须显性的设置,不然默认8848端口
      config:
        file-extension: yaml

No.02-Feign 声明式调用框架

1、Feign优雅替换RestTemplate

  • restTemplate的问题

    image-20211013162213471

  • Feign的使用步骤

image-20211013162320509

代码实现

  • POM依赖修改

    <!-- Feign依赖 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    
  • 入口程序开启@ConfigurationFeignClients

    package com.iyyxx.order;
    
    import com.netflix.loadbalancer.IRule;
    import com.netflix.loadbalancer.RandomRule;
    import com.netflix.loadbalancer.RoundRobinRule;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.client.RestTemplate;
    
    @MapperScan("com.iyyxx.order.mapper")
    @SpringBootApplication
    @EnableFeignClients
    public class OrderApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(OrderApplication.class, args);
        }
    }
    
  • 添加@FeignClient

    package com.iyyxx.order.clients;
    
    import com.iyyxx.user.pojo.User;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    
    @FeignClient("userservice")
    public interface UserClient {
        @GetMapping("/user/{id}")
        User findById(@PathVariable("id") Long id);
    }
    
  • 修改服务层调用

    package com.iyyxx.order.service;
    
    
    import com.iyyxx.order.clients.UserClient;
    import com.iyyxx.order.mapper.OrderMapper;
    import com.iyyxx.order.pojo.Order;
    import com.iyyxx.user.pojo.User;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
    
    @Service
    public class OrderService {
    
        @Autowired
        private OrderMapper orderMapper;
    
        @Autowired
        private UserClient userClient;
    
        public Order queryOrderById(Long orderId) {
            // 1.查询订单
            Order order = orderMapper.findById(orderId);
            // 2.利用userClient查询用户,远程调用且负载均衡
            User user = userClient.findById(order.getUserId());
            // 3.封装user到Order
            order.setUser(user);
            // 4.返回
            return order;
        }
    }
    

2、Feign日志开关

yml配置方式-全局

feign:
  client:
    config:
      default:  #default代表全部,可以用具体被调用的服务名称如userservice
        loggerLevel: full #none,basic,full 空、简要、完整,生产环境不能使用full

yml配置方式-单个

feign:
  client:
    config:
      userservice:  #default代表全部,可以用具体被调用的服务名称如userservice
        loggerLevel: full

bean配置方式-全局

  • 创建DefaultFeignConfiguration

    package com.iyyxx.order.config;
    
    import feign.Logger;
    import org.springframework.context.annotation.Bean;
    
    public class DefaultFeignConfiguration {
    
        @Bean
        public Logger.Level logLevel(){
            return Logger.Level.FULL;	//同样有多种日志级别
        }
    }
    
  • 应用到全局(boot入口程序的@EnableFeignClients的defaultConfiguration配置)

    package com.iyyxx.order;
    
    import com.iyyxx.order.config.DefaultFeignConfiguration;
    import com.netflix.loadbalancer.IRule;
    import com.netflix.loadbalancer.RandomRule;
    import com.netflix.loadbalancer.RoundRobinRule;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.client.RestTemplate;
    
    @MapperScan("com.iyyxx.order.mapper")
    @SpringBootApplication
    @EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)	//入口程序即全局!
    public class OrderApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(OrderApplication.class, args);
        }
    }
    

bean配置方式-单个

  • 配置feignClient的@FeignClient的Configuration属性
package com.iyyxx.order.clients;

import com.iyyxx.order.config.DefaultFeignConfiguration;
import com.iyyxx.user.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value = "userservice",configuration = DefaultFeignConfiguration.class)
public interface UserClient {
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}

3、连接池优化(实际有效参数用jmeter压测)

HttpClient

  • POM依赖

    <!-- Feign HttpClient依赖 -->
    <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-httpclient</artifactId>
    </dependency>
    
  • yml配置

    feign:
      httpclient:
        enabled: true # 开启feign对httpClient的支持
        max-connections: 200  # 最大连接数
        max-connections-per-route: 50 # 每个路径最大连接数
    

OKClient

  • POM依赖

    <!-- Feign OKClient依赖 -->
    <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-okhttp</artifactId>
    </dependency>
    
  • yml配置

    feign:
      okhttp:
        enabled: true
    

4、Feign最佳实践(继承接口-不推荐,统一feignApi可以考虑,如果重叠服务较多的时候)

思路:

  • SpringBootApplication之间不互相引用
    • 另外存放Feign的连接池配置
  • 远程调用都放到Feign-API里面
    • Feign的依赖也放在这个包里
    • 其他Boot都引用他
    • 并且API里面也不去引用具体Boot
    • api项目里主要是client的实现、pojo的冗余和Feign的公共配置
  • api项目可以考虑作为boot之间交互测试的程序==后续在这里做test程序?==

具体实现如下:

  • Feign Model创建,略

  • api project加入feign依赖,order引用api、并去除userservice、feign依赖

    • api/pom依赖

      <dependencies>
          <!-- Feign依赖 -->
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-openfeign</artifactId>
          </dependency>
          <!-- Feign HttpClient依赖 -->
          <dependency>
              <groupId>io.github.openfeign</groupId>
              <artifactId>feign-httpclient</artifactId>
          </dependency>
          <!-- Feign OKClient依赖,可选 -->
          <dependency>
              <groupId>io.github.openfeign</groupId>
              <artifactId>feign-okhttp</artifactId>
          </dependency>
      </dependencies>
      
    • 移植orderservice/clients、orderservice/config、orderservice/pojo,如图

      image-20211014123135301

  • orderservice project删除orderservice的client、config,清理修正pom、

    • pom

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <parent>
              <artifactId>cloud-demo</artifactId>
              <groupId>com.iyyxx</groupId>
              <version>1.0</version>
          </parent>
          <modelVersion>4.0.0</modelVersion>
      
          <artifactId>order-service</artifactId>
      
      
          <dependencies>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-web</artifactId>
              </dependency>
              <dependency>
                  <groupId>mysql</groupId>
                  <artifactId>mysql-connector-java</artifactId>
              </dependency>
              <!--mybatis-->
              <dependency>
                  <groupId>org.mybatis.spring.boot</groupId>
                  <artifactId>mybatis-spring-boot-starter</artifactId>
              </dependency>
      
              <!-- nacos客户端依赖 -->
              <dependency>
                  <groupId>com.alibaba.cloud</groupId>
                  <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
              </dependency>
      
              <!-- 引入自身的feign-api -->
              <dependency>
                  <groupId>com.iyyxx</groupId>
                  <artifactId>feign-api</artifactId>
                  <version>1.0</version>
              </dependency>
      
          </dependencies>
          <build>
              <finalName>app</finalName>
              <plugins>
                  <plugin>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-maven-plugin</artifactId>
                  </plugin>
              </plugins>
          </build>
      
      </project>
      
    • 修正order的user引用为api project

      package com.iyyxx.order.pojo;
      
      import com.iyyxx.feign.pojo.User;
      import lombok.Data;
      
      @Data
      public class Order {
          private Long id;
          private Long price;
          private String name;
          private Integer num;
          private Long userId;
          private User user;
      }
      
    • 修正service的user

      package com.iyyxx.order.service;
      
      
      import com.iyyxx.feign.clients.UserClient;
      import com.iyyxx.feign.pojo.User;
      import com.iyyxx.order.mapper.OrderMapper;
      import com.iyyxx.order.pojo.Order;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      
      @Service
      public class OrderService {
      
          @Autowired
          private OrderMapper orderMapper;
      
          @Autowired
          private UserClient userClient;
      
          public Order queryOrderById(Long orderId) {
              // 1.查询订单
              Order order = orderMapper.findById(orderId);
              // 2.利用userClient查询用户,远程调用且负载均衡
              User user = userClient.findById(order.getUserId());
              // 3.封装user到Order
              order.setUser(user);
              // 4.返回
              return order;
          }
      }
      
    • 调整入口程序,单独扫描clients, 如果要扫描目录可以考虑把 clients换成basePackages

      package com.iyyxx.order;
      
      import com.iyyxx.feign.clients.UserClient;
      import com.iyyxx.feign.config.DefaultFeignConfiguration;
      import com.netflix.loadbalancer.IRule;
      import com.netflix.loadbalancer.RandomRule;
      import com.netflix.loadbalancer.RoundRobinRule;
      import org.mybatis.spring.annotation.MapperScan;
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.cloud.client.loadbalancer.LoadBalanced;
      import org.springframework.cloud.openfeign.EnableFeignClients;
      import org.springframework.context.annotation.Bean;
      import org.springframework.web.client.RestTemplate;
      
      @MapperScan("com.iyyxx.order.mapper")
      @SpringBootApplication
      @EnableFeignClients(clients = UserClient.class, defaultConfiguration = DefaultFeignConfiguration.class)
      public class OrderApplication {
      
          public static void main(String[] args) {
              SpringApplication.run(OrderApplication.class, args);
          }
      }
      
    • application.yml 仅保留feign的连接池配置,==未来如果遇到需要统一连接池可以考虑抽取到api project中==

      ```yaml
      server:
      port: 8080
      spring:
      datasource:
      url: jdbc:mysql://192.168.20.164:3306/cloud_order?useSSL=false
      username: root
      password: 123456
      driver-class-name: com.mysql.jdbc.Driver

    cloud: # nacos settings

    nacos:

    discovery:

    cluster-name: FJ

    namespace: c8f73bfe-ffbd-493b-a9fa-8885c947ca40 # dev测试环境

    mybatis:
    type-aliases-package: com.iyyxx.order.pojo
    configuration:
    map-underscore-to-camel-case: true
    logging:
    level:
    com.iyyxx: debug
    pattern:
    dateformat: MM-dd HH:mm:ss:SSS
    userservice:
    ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
    #com.alibaba.cloud.nacos.ribbon.NacosRule
    #com.netflix.loadbalancer.RandomRule
    ribbon:
    eager-load:
    enabled: true
    clients:
    - userservice
    feign:
    httpclient:
    enabled: true # 开启feign对httpClient的支持
    max-connections: 200 # 最大连接数
    max-connections-per-route: 50 # 每个路径最大连接数
    ```

No.03-Gateway网关

image-20211014141850399

1、GateWay实现

实现过程:

  • 新增model
  • 引入依赖(nacos注册发现、gateway)
  • 编写入口程序(普通springboot)
  • 编写yml文件(服务端口号、nacos注册信息、基本路由规则)
  • 引入依赖

    <!-- 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>
    
  • 入口程序

    package com.iyyxx.gateway;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class GatewayApplication {
        public static void main(String[] args) {
            SpringApplication.run(GatewayApplication.class,args);
        }
    }
    
  • 配置信息

    server:
      port: 10010
    spring:
      application:
        name: gateway
      cloud:
        nacos:
          discovery:
            server-addr: windows10.microdone.cn:80 # nacos settings
        gateway:
          routes:
            - id: user-service  # 路由标识,必须为宜
              uri: lb://userservice
              predicates: # 路由断言
                - Path=/user/**
            - id: order-service  # 路由标识,必须为宜
              uri: lb://orderservice
              predicates: # 路由断言
                - Path=/order/**
    
  • 测试

image-20211014150606079

2、Route Predicate Factories

image-20211014151425961

官方文档参考

可以做的功能:

  • 根据时间范围做活动,比如秒杀 between
  • ip地址范围限定,remoteaddr

案例:添加时间限定,2025年后才可访问,不过没有日志,只有服务404

server:
  port: 10010
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: windows10.microdone.cn:80 # nacos settings
    gateway:
      routes:
        - id: user-service  # 路由标识,必须为宜
          uri: lb://userservice
          predicates: # 路由断言
            - Path=/user/**
        - id: order-service  # 路由标识,必须为宜
          uri: lb://orderservice
          predicates: # 路由断言
            - Path=/order/**
            - After=2025-01-20T17:42:47.789-07:00[America/Denver]

image-20211014152652948

3、GatewayFilter Factory配置

image-20211014151729429

官方文档参考

案例:网关过滤器,

  1. 过滤器对request添加参数,springboot调用并日志输出
  2. 再修改为全局配置
  • gateway/application.yml

    server:
      port: 10010
    spring:
      application:
        name: gateway
      cloud:
        nacos:
          discovery:
            server-addr: windows10.microdone.cn:80
        gateway:
          routes:
            - id: user-service  
              uri: lb://userservice
              predicates: 
                - Path=/user/**
              filters: #添加请求头过滤器,添加请求头
                - AddRequestHeader=Truth,Mike is handsome!
            - id: order-service  # 
              uri: lb://orderservice
              predicates: 
                - Path=/order/**
                - After=2025-01-20T17:42:47.789-07:00[America/Denver]
    
  • userservice/webController

    package com.iyyxx.user.web;
    
    import com.iyyxx.user.config.PatternProperties;
    import com.iyyxx.user.pojo.User;
    import com.iyyxx.user.service.UserService;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.context.config.annotation.RefreshScope;
    import org.springframework.web.bind.annotation.*;
    
    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;
    
    @Slf4j
    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @Autowired
        private UserService userService;
    
        /**
         * 路径: /user/110
         *
         * @param id 用户id
         * @return 用户
         */
        @GetMapping("/{id}")
        public User queryById(@PathVariable("id") Long id,
                              @RequestHeader(value = "Truth", required = false) String truth) {
            System.out.println("truth: " + truth);  //输出
            return userService.queryById(id);
        }
    }
    

    image-20211014154453880

  • 调整为全局设置

    server:
      port: 10010
    spring:
      application:
        name: gateway
      cloud:
        nacos:
          discovery:
            server-addr: windows10.microdone.cn:80 # nacos settings
        gateway:
          routes:
            - id: user-service  
              uri: lb://userservice
              predicates: 
                - Path=/user/**
            - id: order-service  
              uri: lb://orderservice
              predicates: 
                - Path=/order/**
                - After=2025-01-20T17:42:47.789-07:00[America/Denver]
          default-filters:
            - AddRequestHeader=Truth,Lin is handsome!
    

4、Global Filters

说明:这个过滤器是可以编码的!

==优先级==:GWFilter Default Filter > GWFilter Routes Filter > GlobalFilters

GWFilter默认从1算起!
  • 实现

    package com.iyyxx.gateway;
    
    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.stereotype.Component;
    import org.springframework.util.MultiValueMap;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    
    @Component
    public class AuthorizeFilter implements GlobalFilter, Ordered {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            // 1.获取请求参数
            MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
    
            // 2.获取参数中的authorization 参数
            String authorization = queryParams.getFirst("authorization");
    
            // 3。判断参数是否等于admin
            if(authorization!=null && authorization.equals("admin")){
                // 4.是,放行
                return chain.filter(exchange);
            }else{
                // 5.否,拦截, 禁止访问
                exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
                return exchange.getResponse().setComplete();
            }
        }
    
        @Override
        public int getOrder() {
            return -1; //默认优先级21亿,最高-21亿,相比其他过滤器默认排序从1算起,设置-1优先级就很高了
        }
    }
    

5、网关跨域问题

什么是跨域:从浏览器出发,用ajax访问不同的1,2,3级域名,或不同端口,都是跨域!都会被拦截

解决办法:采用CORS方案,在网关程序中集中处理就行, 默认已经处理好,只需要开启配置!

  • vscode添加【live server】插件 ==回头到前端部分,再细研究npm 安装这个并从命令行启动的相关玩法!==

    image-20211014163404938

  • vscode打开文件目录,模拟调用 ctrl+shift+p

image-20211014163530429

image-20211014163546738

  • html测试程序
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<pre>
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"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允许在请求中携带的头信息
            allowCredentials: true # 是否允许携带cookie
            maxAge: 360000 # 这次跨域检测的有效期
</pre>
</body>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
  axios.get("http://localhost:10010/user/1?authorization=admin")
  .then(resp => console.log(resp.data))
  .catch(err => console.log(err))
</script>
</html>
  • 调试程序
spring:
  cloud:
    gateway:
      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
        corsConfigurations:
          '[/**]':
            allowedOrigins: # 允许哪些网站的跨域请求
              - "http://127.0.0.1:5500"
              - "http://www.leyou.com"
            allowedMethods: # 允许的跨域ajax的请求方式
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允许在请求中携带的头信息
            allowCredentials: true # 是否允许携带cookie
            maxAge: 360000 # 这次跨域检测的有效期
  • 查看效果

image-20211014163650215

No.04、企业级服务端nacos、nginx配置

4.1、环境准备

服务 IP 端口 说明
nacos1 192.168.20.162 8848 实际服务端口
nacos2 192.168.20.163 8848 实际服务端口
nacos3 192.168.20.164 8848 实际服务端口
nginx 192.168.20.164 80 反向代理端口

4.2、jdk安装

tar zxvf jdk-8u241-linux-x64.tar.gz 
mv jdk1.8.0_241/ /opt/software
ln -s /opt/software/jdk1.8.0_241 /opt/java

echo 'JAVA_HOME=/opt/java'>>~/.bash_profile 
echo 'JRE_HOME=/opt/java/jre'>>~/.bash_profile 
echo 'PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin'>>~/.bash_profile 
echo 'CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib'>>~/.bash_profile 
echo 'export JAVA_HOME JRE_HOME PATH CLASSPATH'>>~/.bash_profile 


#验证!
java -version

4.3、nacos安装

  • 解压、单机启动、可web访问!
tar xvf nacos-server-1.4.2.tar.gz 
mv nacos/ /opt/software/
ln -s /opt/software/nacos/ /opt/nacos
/opt/nacos/bin/startup.sh -m standalone
/opt/nacos/bin/shutdown.sh
tail -f /opt/nacos/logs/start.out

image-20211014170922035

4.4、nacos#application.properties 配置(服务端口、db)

### Default web server port:
server.port=8848

#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
spring.datasource.platform=mysql

### Count of DB:
db.num=1

### Connect URL of DB:
db.url.0=jdbc:mysql://192.168.20.164:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=123456

4.5、nacos#cluster.conf 集群清单(IP、端口)

192.168.20.162:8848
192.168.20.163
192.168.20.164

4.6、nacos#服务设置、自启动

vim /lib/systemd/system/nacos.service

# 添加以下内容

[Unit]
Description=nacos
After=network.target

[Service]
Type=forking
Environment="JAVA_HOME=/opt/java" 
ExecStart=/opt/nacos/bin/startup.sh 
ExecReload=/opt/nacos/bin/shutdown.sh
ExecStop=//opt/nacos/bin/shutdown.sh
PrivateTmp=true

[Install]
WantedBy=multi-user.target
  • 自启动、重启服务
systemctl enable nacos.service && systemctl restart nacos.service

4.7、nginx#nginx.conf配置(反向代理)

  • 安装pcre、nginx
# 基本环境安装
yum -y install make zlib zlib-devel gcc-c++ libtool  openssl openssl-devel

# 下载pcre
cd /usr/local/src/
wget http://downloads.sourceforge.net/project/pcre/pcre/8.35/pcre-8.35.tar.gz

# 安装pcre
tar zxvf pcre-8.35.tar.gz
cd pcre-8.35
./configure
make && make install
pcre-config --version

# 下载安装nginx
cd ~
wget https://nginx.org/download/nginx-1.21.3.tar.gz
tar xvf nginx-1.21.3.tar.gz 
cd nginx-1.21.3
./configure --prefix=/usr/local/webserver/nginx --with-http_stub_status_module --with-http_ssl_module --with-pcre=/usr/local/src/pcre-8.35
make && make install

# 检查nginx是否安装成功,获取版本号
/usr/local/webserver/nginx/sbin/nginx -v

# 添加web用户
/usr/sbin/groupadd www 
/usr/sbin/useradd -g www www

  • 配置conf文件 vim /usr/local/webserver/nginx/conf/nginx.conf
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;


    upstream nacos-cluster {
        server 192.168.20.162:8848;
        server 192.168.20.163:8848;
        server 192.168.20.164:8848;
    }

    server {
        listen       80;
        server_name  192.168.20.162; 

        location /nacos {
        proxy_pass http://nacos-cluster;
        }
    }

}
  • 配置文件正确性检测 /usr/local/webserver/nginx/sbin/nginx -t
  • nginx配置服务和自启动
vi /usr/lib/systemd/system/nginx.service

# 添加以下内容

[Unit]
Description=nginx
After=network.target
  
[Service]
Type=forking
ExecStart=/usr/local/webserver/nginx/sbin/nginx
ExecReload=/usr/local/webserver/nginx/sbin/nginx -s reload
ExecStop=/usr/local/webserver/nginx/sbin/nginx -s quit
PrivateTmp=true
  
[Install]
WantedBy=multi-user.target
  • 设置nginx自启动

    systemctl enable nginx.service
    systemctl status nginx.service
    reboot
    

4.8、 nginx 操作命令

systemctl stop/restart/start nacos/nginx

评论系统未开启,无法评论!