springcloud+eureka+nacos+feign+gateway的搭建及使用

创建一个父工程maven项目

在这里插入图片描述

字符编码

在这里插入图片描述

java编译版本

在这里插入图片描述

springcloud和springboot版本

  • springcloud必须使用它支持的springboot版本
  • springcloud版本参考:https://spring.io/projects/spring-cloud#overview
  • springAlibaba版本参考:https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
  • 管理依赖,子工程可以继承版本号
  • mvn install 跑一下,子工程就可以自己用父工程的依赖了
  • 删除掉父工程的所有目录留一个pom.xml
      <!-- springcloud的依赖-->
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Hoxton.SR12</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <!-- springboot的依赖-->
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.3.12.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <!--springAlibaba cloud-->
      <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>2.2.8.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>

其他配置

<repositories>
        <repository>
            <id>public</id>
            <name>aliyun nexus</name>
            <url>https://maven.aliyun.com/repository/public</url>
            <releases>
                <enabled>true</enabled>
            </releases>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>public</id>
            <name>aliyun nexus</name>
            <url>https://maven.aliyun.com/repository/public</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
  • 热部署只适用于开发阶段,生产就关掉
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <!--打包时不排除Devtools-->
          <excludeDevtools>false</excludeDevtools>
          <fork>true</fork>
          <addResources>true</addResources>
        </configuration>
      </plugin>

在这里插入图片描述

pom.xml

<?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">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>springcloud</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>

  <name>Maven</name>
  <!-- FIXME change it to the project's website -->
  <url>http://maven.apache.org/</url>
  <inceptionYear>2001</inceptionYear>

  <distributionManagement>
    <site>
      <id>website</id>
      <url>scp://webhost.company.com/www/website</url>
    </site>
  </distributionManagement>

  <properties>
    <java.version>1.8</java.version>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <lombok.version>1.18.20</lombok.version>
    <mysql-connector-java.version>8.0.21</mysql-connector-java.version>
    <druid.version>1.1.8</druid.version>
    <junit.version>4.13</junit.version>
    <log4j.version>1.2.17</log4j.version>
    <mybatis-plus.version>3.2.0</mybatis-plus.version>
  </properties>

  <dependencyManagement>
    <dependencies>

      <!-- springcloud的依赖-->
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Hoxton.SR12</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <!-- springboot的依赖-->
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.3.12.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <!--springAlibaba cloud-->
      <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>2.2.8.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>


      <!--        lombok插件:主要就是使用注解的方式代替get、set、构造方法-->
      <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>${lombok.version}</version>
      </dependency>

      <!--        java连接mysql依赖-->
      <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql-connector-java.version}</version>
      </dependency>

      <!--        配置数据源依赖:连接数据库要用的,这里用的是druid,常见的有c3p0、dbcp等-->
      <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>${druid.version}</version>
      </dependency>

      <!--       junit依赖: 一个单元测试框架 -->
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
        <scope>test</scope>
      </dependency>

      <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus</artifactId>
        <version>${mybatis-plus.version}</version>
      </dependency>

      <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>${log4j.version}</version>
      </dependency>



    </dependencies>
  </dependencyManagement>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.7.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-site-plugin</artifactId>
        <configuration>
          <locales>en,fr</locales>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <reporting>
    <plugins>
      <plugin>
        <artifactId>maven-project-info-reports-plugin</artifactId>
      </plugin>
    </plugins>
  </reporting>
</project>

创建一个api-common子工程

  • 存放封装的HttpResult
  • 存放实体类

在父工程添加子模块

  <modules>
    <module>api-common</module>
  </modules>
  • HttpResult
package com.konglz.apicommon.httpResult;
/**
 * @Description 自定义统一响应体
 * @Param null
 * @Return {@link null}
 * @Author konglz
 * @Date 2022/8/28 22:52
 */

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;


@ApiModel
public class HttpResult<T> {

    @ApiModelProperty(value = "状态码")
    private Integer code;

    @ApiModelProperty(value = "响应信息", notes = "来说明响应情况")
    private String msg;

    @ApiModelProperty(value = "响应的具体数据")
    private T data;

    public HttpResult(ResultEnum resultCodeEnum, T data) {
        this.code = resultCodeEnum.getCode();
        this.msg = resultCodeEnum.getMessage();
        this.data = data;
    }

    public HttpResult(String msg){
        this.msg = msg;
    }

    public HttpResult(T data) {
        this.data = data;
    }

    public HttpResult(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public HttpResult(int value, String message, T data) {
        this.code = value;
        this.msg = message;
        this.data = data;
    }

}
  • ResultEnum
package com.konglz.apicommon.httpResult;
/**
 * @Description 响应枚举码 可以参考参考这个类:HttpStatus
 * @Param null
 * @Return {@link null}
 * @Author konglz
 * @Date 2022/8/28 22:39
 */
public enum ResultEnum {
    //常规错误
    OK(200, "数据响应成功"),
    SERVER_ERROR(500,"服务器异常"),
    NOT_FOUND(404,"未发现资源"),
    BAD_REQUEST(400,"错误的请求"),


    //登录模块
    VERIFY_CODE_ERROR(2006,"验证码错误"),
    USERNAMEORPASSWORD_ERROR(2007,"用户名或者密码错误"),
    REGISTER_VERIFYCODE_SEND_ERROR(2008,"邮箱验证码发送失败"),
    USERNAME_EXIST_ERROR(2009,"该用户名已经存在"),
    EMAIL_EXIST_ERROR(2010,"邮箱已经存在"),
    USER_REGISTER_ERROR(2011,"用户注册失败"),
    REGISTER_CODE_ERROR(2012, "注册码错误"),
    INSERT_MESSGE_ERROR(2013, "插入留言失败"),
    AREADY_COLLECTION(2014, "已经收藏"),

    //参数
    FIELD_VALIDATE_FAIL(1001,"参数校验失败"),

    //异常
    UNKNOWN_CODE(1002,"未知异常"),

    //权限
    UNAUTHORIZED(401,"未授权"),

    //自定义
    CREATE_TOKEN_FAIL(2001,"创建token失败"),
    VERIFY_TOKEN_FAIL(2002,"验证token失败"),
    GET_USERNAME_FROM_TOKEN(2003,"从token获取username失败"),
    GET_CURRENTTIME_FROM_TOKEN(2004,"从token获取currentTime失败"),
    GET_CLAIM_FROM_TOKEN(2005,"从token获取claim失败"),

    NOT_EXISTS_USER(3001,"用户不存在"),

    UNKNOWN_EXCEPTION(5000,"未知异常"),
    TOKEN_EXPIRED_EXCEPTION(5001,"token失效异常");


    private Integer code;
    private String message;

    private ResultEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }


    public Integer getCode() {
        return this.code;
    }

    public String getMessage() {
        return this.message;
    }
}

创建eureka-server子工程

  • 依赖 spring-cloud好像没有eureka的依赖,需要自己写个版本号、父工程依赖
       <parent>
          <groupId>org.example</groupId>
          <artifactId>springcloud</artifactId>
          <version>1.0-SNAPSHOT</version>
       </parent>        

		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            <version>2.2.6.RELEASE</version>
        </dependency>
  • 在启动类添加@EnableEurekaServer注解
  • yml配置
server:
  port: 10086
spring:
  application:
    name: eurekaserver
eureka:
  client:
    service-url:  #eureka的地址信息
      defaultZone: http://127.0.0.1:10086/eureka

  • 注册中心界面

在这里插入图片描述

创建子工程eureka-service子工程

  • 依赖: 父工程、eruka-client
       <parent>
          <groupId>org.example</groupId>
          <artifactId>springcloud</artifactId>
          <version>1.0-SNAPSHOT</version>
       </parent>
        
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.2.6.RELEASE</version>
        </dependency>
  • yml配置,注意不是配置在eureka-service下,在具体模块下配置
spring:
  application:
    name: userservice
eureka:
  client:
    service-url:   #eureka地址信息
      defaultZone: http://localhost:10086/eureka    
  • 从上面可以看出我们其实不需要建一个eureka-service子工程,可以将依赖引入具体的服务即可,在配置yml
  • eureka集群:相互注册

服务拉取

  • 之前讲RestTemplate可以调用帮我们发送一个http请求,请求到别的业务的接口,并返回对应的数据对象例子:首先在启动类注册一个RestTemplate对象,然后使用 restTemplate.getObject(url, Entity.class); 缺点是这种方式是硬编码,不适用于与并发集群、profieles
  • 服务拉取注册中心所有的生产者,现在我们要讲url地址替换为服务名,然后通过@LoadBalanced做负载均衡
String url = "http://userservice/user/";

@Bean
@LoadBalanced
public RestTemplate restTemplate(){
  return new RestTemplate();
}

Ribbon负载均衡

  • 服务器是识别不了"http://userservice/user/"这个地址,会通过Ribbon拉取注册中心的userservice,获得真实的地址,再通过负载均衡算法选一个生产者地址区访问

  • @LoadBalanced是Ribbon默认的策略,是轮询算法实现的

  • 切换负载均衡算法,配置在具体服务的启动类,这种是全局的

@Bean
public IRule randomRule(){		//这里是随机算法
  reutrn new RandomRule();
}

另外一种设置方法局部的针对单一微服务

userservice:
	ribbon:
		NFLoadBalancerClassName: com.netflix.loadbalancer.RandomRule #复杂均衡
  • Ribbon默认使用的是懒加载,第一次非常慢
  • 将Ribbon设置未饿加载,写在具体服务中
ribbon
	eager-load:
		enable: true #开启饿加载
		clients:     #是一个集合多个写成下面这样
			-userService
			-orderService

Nacos下载

  • 下载:https://github.com/alibaba/nacos

在这里插入图片描述

在这里插入图片描述

  • 启动命令
    • windows: startup.cmd -m standalone (单机启动)
    • linux: sh startup.sh -m standalone

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

nacos引入

  • 父工厂引入springcloud-alibaba的依赖(注意版本问题)
      <!--springAlibaba cloud-->
      <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>2.2.8.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
  • 具体业务引入nacos服务发现依赖(没有starter-web的话可能导致管理页面不显示服务)
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>       
  • 在具体业务的配置文件中配置
spring:
  application:
    name: userService
  cloud:
    nacos:
      server-addr: localhost:8848

在这里插入图片描述

nacos服务存储模型

  • 服务
    • 集群: 同在一个地域的实例被称为集群,能够防止熔灾
      • 实例
  • 在服务中配置集群名称
spring:
  application:
    name: userService
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: HZ

点击服务的详情可看到服务所在的集群

在这里插入图片描述

  • 配置优先访问同集群,然后随机访问同集群下的实例
spring:
  application:
    name: xxxService
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: HZ
userService:
  ribbon:
    NFLoadBalancerClassName: com.alibaba.cloud.nacos.ribbon.NacosRule #复杂均衡
  • 配置同集群下实例的权重,可以将权重配置为0,但是该服务将不会被使用方便用于更新版本

在这里插入图片描述

nacos环境隔离

  • namespace:默认的命名空间是public
    • group
      • service/data(实例)

在这里插入图片描述

  • 修改服务的命名空间

在这里插入图片描述

spring:
  application:
    name: userService
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: HZ
        namespace: 19da4d50-37b3-4d37-ac66-35226066f37e

注册中心nacos与eureka对比

相同:

  • 支持服务注册和服务拉取、会定时拉取注册中心的数据,服务消费存在一个服务缓存列表

不同:

  • nacos会见服务提供者划分为:临时实例、永久实例 (默认是临时实例),临时实例用的是心跳检测、非临时实例(永久实例)会被nocas主动询问,永久实例不会被nocas剔除,会显示这个实例是否健康
  • nocas会主动推送变更消息给消费者
  • nocas集群默认采用AP方式、当集群中存在非临时实例会采用CP模式、eureka采用AP模式
spring:
  application:
    name: userService
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: HZ
        namespace: 19da4d50-37b3-4d37-ac66-35226066f37e
        ephemeral: true	#将实例设置为永久实例

nacos配置管理

服务器多的时候,方便管理,所以nacos配置管理

  • 配置更改热更新

在这里插入图片描述

在这里插入图片描述

服务获取nocas统一配置

在这里插入图片描述

  • 依赖
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
  • 在resource下创建boostrap.yml: 因为在application.yml前执行的bootstap.yml,服务启动前需要获取nacos配置的一些信息
spring:
  application:
    name: userService
  profiles:
    active: dev
  cloud:
    nacos:
      server-addr: localhost:8848
      config:
        file-extension: yaml
  • 测试
package com.konglz.user.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

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

/**
 * @Description
 * @Author konglz
 * @Data 2022/9/26 12:14
 */
@RestController
public class TestController {

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

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

在这里插入图片描述

nacos配置热更新

  • 第一种: @Value所在的类加上@RefreshScope

在这里插入图片描述

  • 第二种: @ConfigurationProperties(prefix = “pattern”)
@Data
@ConfigurationProperties(prefix = "pattern")
@Component
public class PatternProperties {
    private String date;
}

nacos多环节配置共享

  • userService.yml: 配置一些多环境都需要的配置,这里面的配置一定会被加载,优先级是带环境的高于这个
    • userService-dev.yml
    • userService-prod.yml
    • userService-test.yml

nacos集群搭建

  • 将cluster.conf.example改为cluster.conf
#因为只有一台机器,这里使用不同端口号代表3台机器
127.0.0.1:8848
127.0.0.1:8849
127.0.0.1:8847
  • application.properties打开关于数据源的配置
#*************** 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://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=nacos
db.password.0=nacos
  • nginx.conf配置
upstream nocas-cluster{
  server 127.0.0.1:8848;
  server 127.0.0.1:8848;
  server 127.0.0.1:8847
}

server {
  listen: 80;
  server_name: localhost;
  
  location /nacos {
    proxy_pass http://nacos-cluster;
  }
}
  • 服务配置集群地址
#端口号与nginx的listen一直,ip地址应该可以在集群的地址中选一个
server-addr: 服务器地址:80

feign远程调用

  • 之前讲的服务拉取用的是RestTemplate,它不支持集群,采用的是硬编码不好管理

  • feign是一个声明式的http客户端,feign集成了负载均衡,支持Restful(表现层状态转移)的接口,代替了RestTemplate

  • 依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
  • 启动类添加开启feign的注解
@EnableFeignClients
  • 编写Feign客户端:在其它服务中创建userService服务的客户端,实现userService服务的远程调用
package com.kongz.role.clients;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @Description
 * @Author konglz
 * @Data 2022/9/26 13:42
 */
@FeignClient("userServie")
public interface UserClient {
    @GetMapping("/user/id")
    User findUserById(@PathVariable("id") Long id);
}
//调用
@Autowired
UserClient userClient;

userClient.方法名();

feign的自定义配置

类型作用说明
feign.Logger.Level修改日志级别包含四种不同的级别:NONE、BASIC、HEADERS、FULL
feign.codec.Decoder响应结果的解析器http远程调用的结果做解析,例如解析json字符串为java对象
feign.codec.Encoder请求参数编码将请求参数编码,便于通过http请求发送
feign. Contract支持的注解格式默认是SpringMVC的注解
feign. Retryer失败重试机制请求失败的重试机制,默认是没有,不过会使用Ribbon的重试
  • feign日志的两种配置第一种
feign:  
  client:
    config: 
      userservice: # 针对某个具体微服务的配置(配置服务名即可)
        loggerLevel: FULL #  日志级别 
        
        
feign:  
  client:
    config: 
      default: # 针对全局微服务的配置,用default即可
        loggerLevel: FULL #  日志级别 


  • feign日志的两种配置第二种
//加在具体的Client上(具体业务)
@FeignClient(value = "userServie",configuration = DefaultFeignConfiguration.class)
//加载启动类(全局)
@SpringBootApplication
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
public class RoleServiceApplication {

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

feign的性能优化

  • Feign的底层客户端实现
    • URLConnection: 默认实现,不支持连接池
    • Apache HttpClient: 支持连接池
    • OKHttp: 支持连接池
  • 优化:
    • 不使用默认URLConnection,使用支持连接池的底层实现
    • 日志级别使用Basic(必要的请求相应信息)或者none(无),减少性能损耗
  • 依赖
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>
  • 连接池配置
feign:
  client:
    config:
      default:
        loggerLevel: FULL

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

feign的最佳实践

  • 方式一:继承的思想,给消费者的FeignClient和提供者的controller定义统一的父接口作为标准,上面的feign远程调用就是这种方式实现的,这种方式耦合度太高,官方不推荐

  • 方式二:抽取的思想,创建一个feign-api项目,服务用的时候直接添加feign-api依赖,但是会将一些不需要的东西引入服务

  • 创建一个feign-api项目

    • 创建一个clients包: 存放所有的服务调用要用的接口
    • 创建一个config包: 配置自定义Feign
    • 创建一个pojo包: 存放实体类
  • 依赖:使用feign-api

<dependency>
    <groupId>com.example</groupId>
    <artifactId>feign-api</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>
//启动类配置
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)

  • feignClient不在springbootApplication的扫描范围时,第一种解决方式(扫描所有的client)
@EnableFeignClients(basePackages = "com.example.feign-api",defaultConfiguration = DefaultFeignConfiguration.class)
  • feignClient不在springbootApplication的扫描范围时,第二种解决方式(加载指定的client)
@EnableFeignClients(clients = {UserClient.class},defaultConfiguration = DefaultFeignConfiguration.class)

搭建网关服务

  • 创建一个网关的项目
  • 依赖
<!--服务注册依赖-->    
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 网关依赖 -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
  • 配置路由
server:
  port: 10010
spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: localhost:8848
    gateway:
      routes:
        - id: user-service # 路由id,自定义,只要唯一即可
          #uri: http://localhost:8080 #路由的目标地址 http就是固定地址
          uri: lb://userService #路由的目标地址 lb就是负载均衡, 后面跟的是服务名称
          predicates: #路由断言,也就是判断请求是否符合路由规则的要求
            - Path=/user/**  #这个是按照路径匹配,只要以/user/开头就符合要求
        - id: role-service
          uri: lb://orderServicce
          predicates:
            - Path=/order/**
  • 断言工厂官网参考:https://docs.spring.io/spring-cloud-gateway/docs/3.1.4-SNAPSHOT/reference/html/#gateway-request-predicates-factories

网关过滤器

  • 过滤器官网参考:https://docs.spring.io/spring-cloud-gateway/docs/3.1.4-SNAPSHOT/reference/html/#gatewayfilter-factories
server:
  port: 10010
spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: localhost:8848
    gateway:
      routes:
        - id: user-service # 路由id,自定义,只要唯一即可
          #uri: http://localhost:8080 #路由的目标地址 http就是固定地址
          uri: lb://userService #路由的目标地址 lb就是负载均衡, 后面跟的是服务名称
          predicates: #路由断言,也就是判断请求是否符合路由规则的要求
            - Path=/user/**  #这个是按照路径匹配,只要以/user/开头就符合要求
          filters:
            - AddRequestHeader=author, klz
  • 测试
    @GetMapping("/prop")
    public PatternProperties properties(@RequestHeader(value = "author",required = false)String author){
        System.out.println(author);
        return patternProperties;
    }
  • 配置全局路由
server:
  port: 10010
spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: localhost:8848
    gateway:
      routes:
        - id: user-service # 路由id,自定义,只要唯一即可
          #uri: http://localhost:8080 #路由的目标地址 http就是固定地址
          uri: lb://userService #路由的目标地址 lb就是负载均衡, 后面跟的是服务名称
          predicates: #路由断言,也就是判断请求是否符合路由规则的要求
            - Path=/user/**  #这个是按照路径匹配,只要以/user/开头就符合要求
        - id: role-service
          uri: lb://orderServicce
          predicates:
            - Path=/order/**
      default-filters: 
        - AddRequestHeader=author, klz

网关自定义全局过滤器GobalFilter

  • 与default-filters一样是全局的,但是前者是约定好的,如果要采用编程式自定义需要编写的类实现GobalFilter
  • 执行顺序(order一样): default_filters > filter > gobalFilter , order越小执行越早
package com.konglz.gateway;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @Description
 * @Author konglz
 * @Data 2022/9/26 15:49
 */
@Order(-1)
@Component
public class AuthrizationFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取请求参数
        ServerHttpRequest request = exchange.getRequest();
        MultiValueMap<String,String> params = request.getQueryParams();
        String auth = params.getFirst("Authorization");
        if("admin".equals(auth)){
            return chain.filter(exchange);
        }
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        return exchange.getResponse().setComplete();

    }
}

网关配置跨域

  • 跨域:域名不一致就是跨域,包括:端口号、二级域名、一级域名不同
  • 跨域问题:浏览器禁止请求的发起者与服务端发生跨域请求ajax,请求将被浏览器拦截
spring:
  cloud:
    gateway:
      # 。。。
      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
        corsConfigurations:
          '[/**]':
            allowedOrigins: # 允许哪些网站的跨域请求 
              - "*"			# 都能访问
              #- "http://localhost:8080"
            allowedMethods: # 允许的跨域ajax的请求方式
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允许在请求中携带的头信息
            allowCredentials: true # 是否允许携带cookie
            maxAge: 360000 # 这次跨域检测的有效期
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring CloudSpring Cloud Alibaba都是基于Spring Framework的开源框架,用于构建分布式系统和微服务架构。它们都提供了一系列的组件和工具来简化微服务开发和管理。 Spring Cloud是一个由Pivotal团队维护的项目,它集成了Netflix开源的一些组件,如Eureka作为注册中心、Ribbon作为负载均衡器、Feign作为服务调用工具等。同时,Spring Cloud还提供了其他功能,如Config Server用于动态管理配置、Gateway用于构建API网关等。 而Spring Cloud Alibaba则是阿里巴巴开源的项目,它在Spring Cloud的基础上进行了扩展和定制,增加了一些阿里巴巴自己的组件和工具。比如,它使用Nacos作为注册中心和配置中心,使用Sentinel作为熔断降级工具。 总的来说,Spring CloudSpring Cloud Alibaba都是用于构建微服务架构的框架,它们的区别在于Spring Cloud集成了Netflix组件,而Spring Cloud Alibaba集成了阿里巴巴的一些组件。根据具体的需求和技术栈选择使用哪个框架可以更好地满足开发和管理微服务的需求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Spring Cloud Alibaba和Spring Cloud的区别](https://blog.csdn.net/weixin_43888891/article/details/126653270)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值