目录
1.准备三个nacos服务器---为了操作方便统一部署到同一台电脑
配置集群
在实际开发过程中,如果使用Nacos的话,为了确保高可用,我们一般都会对其进行集群的部署。Nacos规定集群中Nacos节点的数量需要大于等于3个;同时,单机模式下Nacos的数据默认保存在其内嵌数据库中deby,不方便观察数据存储的基本情况。而且如果集群中启动多个默认配置下的Nacos节点,数据存储是存在一致性问题的。为了解决这个问题,Nacos采用了集中式存储的方式来支持集群化部署,目前只支持MySQL的存储;此外,我们还需要借助Nginx实现负载均衡。这一过程的部署架构图如下所示:
1.准备三个nacos服务器---为了操作方便统一部署到同一台电脑
1.1 创建数据库

1.2 指定使用mysql作为数据存储
1.3 配置集群文件
1.4 停止nacos并复制三份
并修改每一份的端口号
1.5 启动三个nacos
1.6 搭建nginx代理上面三个nacos
1.7 微服务注册到nacos集群上
2 网关简介
大家都都知道在微服务架构中,一个系统会被拆分为很多个微服务。那么作为客户端(pc androud ios 平板)要如何去调用这么多的微服务呢?如果没有网关的存在,我们只能在客户端记录每个微服务的地址,然后分别去调用。 axios.get(ip:port/url) axios.get(ip:port/url)
这样的架构,会存在着诸多的问题:
客户端多次请求不同的微服务,增加客户端代码或配置编写的复杂性
认证复杂,每个服务都需要独立认证。
存在跨域请求,在一定场景下处理相对复杂。
(跨域: 浏览器的ajax从一个地址访问另一个地址:
协议://ip:port 如果三则有一个不同,则会出现跨域问题。
http://192.168.10.11:8080 ----->https://192.168.10.11:8080
http://127.0.0.1:8080--->http://localhost:8080 跨域
)
上面的这些问题可以借助API网关来解决。
3 Gateway简介
Spring Cloud Gateway是Spring公司基于Spring 5.0,Spring Boot 2.0 和 Project Reactor 等术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。它的目标是替代 Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控和限流。
优点:
性能强劲:是第一代网关Zuul的1.6倍
功能强大:内置了很多实用的功能,例如转发、监控、限流等
设计优雅,容易扩展.
缺点:
其实现依赖Netty与WebFlux,不是传统的Servlet编程模型,学习成本高
不能将其部署在Tomcat、Jetty等Servlet容器里,只能打成jar包执行 web.Jar
需要Spring Boot 2.0及以上的版本,才支持
gateway内置了服务器 netty服务器。
4 Gateway快速入门
要求: 通过浏览器访问api网关,然后通过网关将请求转发到商品微服务
4.1 创建一个gateway的工程并加入依赖
<?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>qy151-dyt-parent</artifactId>
<groupId>com.dyt</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>qy151-dyt-gateway</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
<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>
</dependencies>
</project>
4.2 创建启动类
package com.dyt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author dyt
*/
@SpringBootApplication
public class GatewayApp {
public static void main(String[] args){
SpringApplication.run(GatewayApp.class,args);
}
}
4.3 修改配置文件
server:
port: 7001
spring:
application:
name: dyt-gateway
cloud:
nacos:
discovery:
register-enabled: false
server-addr: localhost:81
#
# gateway:
# discovery:
# locator:
# enabled: true
gateway:
routes:
- id: xzj-order
uri: lb://order
predicates:
- Path=/order/**
- id: xzj-product
uri: lb://product
predicates:
- Path=/product/**
filters:
- SetStatus=300
4.4 启动项目, 并通过网关去访问微服务
5 让gateway网关从注册中心拉取服务型
5.1 让gateway网关从注册中心拉取服务型
(1)引入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
(2)配置文件中指定注册中心的地址
发现: 有一个微服务需要配置一个路由,如果这时增加一个新的微服
务,则需要在配置文件中增加一个新的路由配置。
能不能自动路由转发微服务呢!====能
5.2 gateway自动路由
修改配置文件:
访问时:
http://网关的ip:网关的port/微服务名称/资源路径
5.3 介绍Gateway断言
SpringCloud Gateway包括许多内置的断言工厂,所有这些断言都与HTTP请求的不同属性匹配体如下:
基于Datetime类型的断言工厂
此类型的断言根据时间做判断,主要有三个:
AfterRoutePredicateFactory: 接收一个日期参数,判断请求日期是否晚于指定日期
BeforeRoutePredicateFactory: 接收一个日期参数,判断请求日期是否早于指定日期
BetweenRoutePredicateFactory: 接收两个日期参数,判断请求日期是否在指定时间段内
5.4 过滤器
5.4 全局过滤器
作用: 认证校验 黑白名单 敏感词
(1) 如何定义全局过滤器。
package com.dyt.filter;
import com.alibaba.fastjson.JSON;
import com.dyt.entity.Anon;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
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.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
/**
* @author dyt
*/
@Component
public class LoginFilter implements GlobalFilter, Ordered {
@Autowired
private Anon anon;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
String path = request.getPath().toString();
System.out.println(request);
System.out.println(path);
System.out.println(anon.getUrl());
if(anon.getUrl().contains(path)){
return chain.filter(exchange);
}
String token = request.getHeaders().getFirst("token");
if (StringUtils.hasText(token)&&"admin".equals(token)){
return chain.filter(exchange);
}
//3.返回一个json数据。
//3.1设置状态码
response.setStatusCode(HttpStatus.UNAUTHORIZED);
//3.2封装返回数据
Map<String, Object> map = new HashMap<>();
map.put("msg", "未登录");
map.put("code", 4000);
//3.3作JSON转换
byte[] bytes = JSON.toJSONString(map).getBytes(StandardCharsets.UTF_8);
//3.4调用bufferFactory方法,生成DataBuffer对象
DataBuffer buffer = response.bufferFactory().wrap(bytes);
//4.调用Mono中的just方法,返回要写给前端的JSON数据
return response.writeWith(Mono.just(buffer));
}
//优先级 返回的值越小优先级越高
@Override
public int getOrder() {
return 0;
}
}
package com.dyt.entity;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author dyt
*/
@Component
@ConfigurationProperties(prefix = "anon")
public class Anon {
private List<String> url;
public List<String> getUrl() {
return url;
}
public void setUrl(List<String> url) {
this.url = url;
}
}
application.properties
anon.url[0]=/sso/login
anon.url[1]=/product/getMsg
application.yml
server:
port: 7000
spring:
application:
name: springcloud-gateway
# cloud:
# gateway:
# discovery:
# locator:
# enabled: true
# nacos:
# server-addr: localhost:81
cloud:
gateway:
routes:
- id: springcloud-order
uri: lb://nacos-order
predicates:
- Path=/order/**
filters:
- SetStatus=300- id: springcloud-product
uri: lb://nacos-product
predicates:
- Path=/product/**
#anon:
# url:
# - /sso/login
# - /product/getMsgnacos:
discovery:
server-addr: localhost:81
register-enabled: false
定义一个
@GetMapping("/getMsg")
public String getMsg(){
return "getMsg*****";
}
6 nacos配置管理
(1) 创建列表中添加配置文件
nacos.order
server.port=8091
#日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
spring.cloud.nacos.discovery.server-addr=localhost:81
#spring.cloud.nacos.discovery.register-enabled=false
spring.application.name=nacos-order
#eureka.client.register-with-eureka=false
#eureka.client.service-url.defaultZone=http://localhost:7001/eureka
nacos-product.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
nacos.product
#为了后期扩展方便商品微服务的端口设置为8080~8089之间
server.port=8081
#日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
spring.application.name=nacos-product
#eureka.client.service-url.defaultZone=http://localhost:7001/eureka
datasource.propertiess数据源
# 数据源
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql://localhost:3306/springcloud?serverTimezone=Asia/Shanghai
spring.datasource.druid.username=root
spring.datasource.druid.password=pAssW0rd
nacos.properties
spring.cloud.nacos.discovery.server-addr=localhost:81
(2)加入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
(3) 建一个bootstrap.propreties配置文件
spring.application.name=nacos-order
spring.cloud.nacos.config.file-extension=properties
spring.cloud.nacos.config.server-addr=localhost:81
#配置数据源
spring.cloud.nacos.config.extension-configs[0].data-id=datasource.properties
spring.cloud.nacos.config.extension-configs[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.extension-configs[0].refresh=true
spring.cloud.nacos.config.extension-configs[1].data-id=nacos.properties
spring.cloud.nacos.config.extension-configs[1].group=DEFAUL_GROUP
spring.cloud.nacos.config.extension-configs[1].refresh=true
(4) 测试