最近nacos非常火,很多使用eureka的都替换成nacos,既可以做注册中心也可以做配置中心,除此之外还有更好用的功能,今天说一下nacos和gateway做动态路由。
动态路由网上一搜一大堆,真正好使的没几个,其实有更加直接的方式,nacos已经提供了。下面我们一步步看看动态路由怎么配置。
一、Nacos + Gateway动态网关
1.1 引入nacos依赖
在你的gateway项目,和其他微服务中引入nacos,分别是注册中心和配置中心。
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-nacos-discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>${nacos.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-nacos-config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>${nacos.version}</version>
</dependency>
<nacos.version>2.2.1.RELEASE</nacos.version>
1.2 gateway配置文件
重点就在以下配置文件的带注释的这一行,这个可以主动将注册中心的服务拉取到网关作为路由,当新服务注册到naocs,会直接添加到网关路由中;从nacos下线的服务会从网关中去除。对比网上增加配置文件,以及代码的动态网关要方便很多。并且不需要在网关中配置路由信息。
spring:
profiles:
active: dev
application:
name: bssp-gateway-service
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
namespace: 3a44ef28-b35c-44bb-8cd2-873c14ebc911
group: DEFAULT_GROUP
file-extension: yml
discovery:
server-addr: 127.0.0.1:8848
namespace: 3a44ef28-b35c-44bb-8cd2-873c14ebc911
gateway:
discovery:
locator:
enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由
1.3 服务调用
通过网关加服务名称调用服务接口:
http://localhost:8888/bssp-user-service/user/info/getById?id=1
结果:
{
"code": 0,
"data": {
"limit": null,
"page": null,
"id": "1",
"nickname": "weirx",
"realName": "--",
"username": "weirx",
"password": "$2a$10$syz1K7t47gJZ79cIs7o0gOvS6hQO7AMlOlEWWKtxtrlJ/jLRRj4iy",
"sex": 1,
"phone": "13339411800",
"certificatesType": 1,
"certificatesNum": 230523199203134013,
"address": null,
"source": 1,
"isDelete": 0,
"createTime": "2020-07-23 14:06:56",
"updateTime": null
},
"msg": "操作成功"
}
二、网关整合knife4j
2.1 引入依赖
在每个服务和网关中引入以下依赖
<!-- knife4j -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.3</version>
</dependency>
2.2 配置文件
在每个服务中增加以下配置,gateway除外,用于在接口界面展示基本信息。
swagger:
enabled: true
title: 用户服务
base-package: com.cloud.bssp.admin
version: V1.0
description: 后台admin服务
license: Apache License, Version 2.0
license-url: https://www.apache.org/licenses/LICENSE-2.0.html
terms-of-service-url: http://localhost:8002/doc.html
contact: xxxxxxxxxxxx@gmail.com
authorization: #有auth2 并使用以前的swagger-ui
key-name: Authorization
2.3 增加两个类
package com.cloud.bssp.gateway.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.*;
import java.util.Optional;
@RestController
@RequestMapping("/swagger-resources")
public class SwaggerHandler {
/**
* 权限配置,没有的不用关注
*/
@Autowired(required = false)
private SecurityConfiguration securityConfiguration;
@Autowired(required = false)
private UiConfiguration uiConfiguration;
private final SwaggerResourcesProvider swaggerResources;
@Autowired
public SwaggerHandler(SwaggerResourcesProvider swaggerResources) {
this.swaggerResources = swaggerResources;
}
@GetMapping("/configuration/security")
public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));
}
@GetMapping("/configuration/ui")
public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
}
/**
* 获取接口信息
* @date: 2020/12/3
* @param
* @return reactor.core.publisher.Mono<org.springframework.http.ResponseEntity>
* @author weirx
* @version 3.0
*/
@GetMapping("")
public Mono<ResponseEntity> swaggerResources() {
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
}
}
package com.cloud.bssp.gateway.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Component
public class SwaggerProvider implements SwaggerResourcesProvider {
/**
* 接口地址
*/
public static final String API_URI = "/v2/api-docs";
/**
* 路由加载器
*/
@Autowired
private RouteLocator routeLocator;
/**
* 网关应用名称
*/
@Value("${spring.application.name}")
private String applicationName;
@Override
public List<SwaggerResource> get() {
//接口资源列表
List<SwaggerResource> resources = new ArrayList<>();
//服务名称列表
List<String> routeHosts = new ArrayList<>();
// 获取所有可用的应用名称
routeLocator.getRoutes().filter(route -> route.getUri().getHost() != null)
.filter(route -> !applicationName.equals(route.getUri().getHost()))
.subscribe(route -> routeHosts.add(route.getUri().getHost()));
// 去重,多负载服务只添加一次
Set<String> existsServer = new HashSet<>();
routeHosts.forEach(host -> {
// 拼接url
String url = "/" + host + API_URI;
//不存在则添加
if (!existsServer.contains(url)) {
existsServer.add(url);
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setUrl(url);
swaggerResource.setName(host);
resources.add(swaggerResource);
}
});
return resources;
}
}
2.4 结果
访问以下地址:http://localhost:8888/doc.html
![](https://img.haomeiwen.com/i16830368/9dee46a6c96e8010.png)
网友评论