⑥SpringCloud 实战:引入gateway组件,开启网关路由功能
这是SpringCloud实战系列中第4篇文章,了解前面第两篇文章更有助于更好理解本文内容:
①SpringCloud 实战:引入Eureka组件,完善服务治理
②SpringCloud 实战:引入Feign组件,发起服务间调用
③SpringCloud 实战:使用 Ribbon 客户端负载均衡
④SpringCloud 实战:引入Hystrix组件,分布式系统容错
⑤SpringCloud 实战:引入Zuul组件,开启网关路由
简介
Spring Cloud Gateway 是 Spring Cloud 的一个子项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。
Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。
特性
Spring Cloud Gateway 具有如下特性:
- 基于Spring Framework 5, Project Reactor 和 Spring Boot 2.0 进行构建;
- 动态路由:能够匹配任何请求属性;
- 可以对路由指定 Predicate(断言)和 Filter(过滤器);
- 集成Hystrix的断路器功能;
- 集成 Spring Cloud 服务发现功能;
- 易于编写的 Predicate(断言)和 Filter(过滤器);
- 请求限流功能;
- 支持路径重写。
实战 Gateway
引入 gateway
新建
jlw-gateway
项目引入gateway依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
加入Eureka注册中心
开启服务注册和发现
# gateway 服务端口
server:
port: 9000 spring:
cloud:
gateway:
discovery:
locator:
# 启用DiscoveryClient网关集成的标志
enabled: true
# 服务小写匹配
lower-case-service-id: true
配置完上面,Gateway 就可以自动根据服务发现为每个服务创建router了,然后将已服务名开头的请求路径转发到对应的服务。
Gateway Actuator API
pom中引入spring-boot-starter-actuator相关依赖,然后配置文件添加如下代码,开启gateway相关的端点。
management:
endpoints:
web:
exposure:
#应该包含的端点ID,全部:*
include: 'gateway'
重启项目,访问http://localhost:9000/actuator/gateway/routes就可以查看到配置的路由信息了
更多gateway路由信息接口展示如下图:
相关概念
- Route(路由):
路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由; - Predicate(断言):
指的是Java 8 的 Function Predicate。 输入类型是Spring框架中的ServerWebExchange。 这使开发人员可以匹配HTTP请求中的所有内容,例如请求头或请求参数。如果请求与断言相匹配,则进行路由; - Filter(过滤器):
指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前后对请求进行修改。
路由基本配置
Gateway 提供了两种不同的方式用于配置路由:一种是通过yml文件来配置,另一种是通过Java Bean来配置
①使用配置文件
spring:
cloud:
gateway:
routes:
- id: eureka-provider
uri: lb://eureka-provider
predicates:
- Path=/api/ep/**
filters:
- StripPrefix=2
字段含义解释:
- id
我们自定义的路由 ID,保持唯一 - uri
目标服务地址,大部分场景我们是转发到某个服务上,配置lb://eureka-provider
意思是请求要转发到注册中心的eureka-provider
服务上。 - predicates
路由条件,接受一个参数,返回一个布尔结果决定是否匹配。Gateway 为我们内置了多种路由条件,包括 Path、Cookie、Param、Header、Before、After 等等,开箱即用,当然我们也可以自己实现 predicates - filters
过滤规则,当请求经过 predicate 匹配成功后,执行 filter,我们可以使用它修改请求和响应,示例表示目标服务收到的 path 将会忽略2位路径path。
②使用Java Bean配置
配置RouteLocator
对象,代码示例如下:
@Bean
public RouteLocator customRoutes(RouteLocatorBuilder builder){
return builder.routes()
// 请求网关路径包含 /api/ec/** 的都会被路由到eureka-client
.route("eureka-client",r->r.path("/api/ec/**")
.filters(f->f.stripPrefix(2))
.uri("lb://eureka-client"))
// 可以配置多个route
.route("eureka-client2",r->r.path("/api/ec2/**")
.filters(f->f.stripPrefix(2))
.uri("lb://eureka-client"))
.build();
}
以上配置后,通过http://localhost:9000/api/ec/sayHello 或者http://localhost:9000/api/ec2/sayHello 都会被路由到eureka-client
服务。
路由规则:Predicate
Spring Cloud Gateway 内置了很多 Predicates 工厂(可以通过访问路径/actuator/gateway/routepredicates
查看),这些 Predicates 工厂通过不同的 HTTP 请求参数来匹配,多个 Predicates 工厂可以组合使用。
按照其功能可以大致分为以下几种不同 Predicate
1.通过请求时间匹配路由
在
指定时间之后
的请求会匹配该路由:AfterRoutePredicateFactoryspring:
cloud:
gateway:
routes:
- id: ribbon-client
uri: lb://ribbon-client
predicates:
- After=2019-10-10T00:00:00+08:00[Asia/Shanghai]
在
指定时间之前
的请求会匹配该路由:BeforeRoutePredicateFactoryspring:
cloud:
gateway:
routes:
- id: ribbon-client
uri: lb://ribbon-client
predicates:
- Before=2019-10-10T00:00:00+08:00[Asia/Shanghai]
在
指定时间区间
内的请求会匹配该路由:BetweenRoutePredicateFactory
spring:
cloud:
gateway:
routes:
- id: ribbon-client
uri: lb://ribbon-client
predicates:
- Between=2019-10-01T00:00:00+08:00[Asia/Shanghai], 2019-10-10T00:00:00+08:00[Asia/Shanghai]
2.通过Cookie匹配路由
Cookie Route Predicate 可以接收两个参数,一个是 Cookie name,一个是正则表达式。示例如下:
spring:
cloud:
gateway:
routes:
- id: ribbon-client
uri: lb://ribbon-client
predicates:
- Cookie=name, jinglingwang.cn
3.通过 Header匹配路由
Header Route Predicate 和 Cookie Route Predicate 一样,也是接收 2 个参数,一个 header 中属性名称和一个正则表达式,示例如下:
spring:
cloud:
gateway:
routes:
- id: ribbon-client
uri: lb://ribbon-client
predicates:
- Header=name, jinglingwang.cn
4.通过 Host 匹配路由
该模式接收一个参数:主机列表,示例如下:
spring:
cloud:
gateway:
routes:
- id: ribbon-client
uri: lb://ribbon-client
predicates:
- Host=**.jinglingwang.cn,**.jinglingwang.com
5.通过 Request Method 匹配路由
可以通过是 POST、GET、PUT、DELETE 等不同的请求方式来进行路由,示例代码如下:
spring:
cloud:
gateway:
routes:
- id: ribbon-client
uri: lb://ribbon-client
predicates:
- Method=GET,POST
6.通过请求路径匹配路由
spring:
cloud:
gateway:
routes:
- id: ribbon-client
uri: lb://ribbon-client
predicates:
- Path=/api/rc/**
7.通过请求参数匹配路由
该模式有两个参数:一个必需的param和一个可选的regexp(Java正则表达式),示例如下
spring:
cloud:
gateway:
routes:
- id: ribbon-client
uri: lb://ribbon-client
predicates:
- QUERY=name,jingling*
8.通过指定远程地址匹配路由
spring:
cloud:
gateway:
routes:
- id: ribbon-client
uri: lb://ribbon-client
predicates:
- RemoteAddr=192.168.1.1/24 #192.168.1.1是IP 24是子网掩码
如果请求的远程地址是192.168.1.10,则此路由匹配。
9.通过权重来匹配路由
该模式有两个参数:group和Weight(一个int值),示例如下:
spring:
cloud:
gateway:
routes:
- id: weight_high
uri: http://localhost:8201
predicates:
- Weight=group1, 8
- id: weight_low
uri: http://localhost:8202
predicates:
- Weight=group1, 2
以上表示有80%的请求会被路由到localhost:8201,20%会被路由到localhost:8202
网关过滤器
路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路由过滤器只能指定路由进行使用。Spring Cloud Gateway 内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生。
添加请求Header过滤器
spring:
cloud:
gateway:
routes:
- id: ribbon-client
uri: lb://ribbon-client
filters:
- AddRequestHeader=source, jinglingwang.cn
上面的示例会为所有匹配的请求向下游请求时在Header中添加
source=jinglingwang.cn
添加请求参数过滤器
spring:
cloud:
gateway:
routes:
- id: ribbon-client
uri: lb://ribbon-client
filters:
- AddRequestParameter=source, jinglingwang.cn
上面的示例会把
source=jinglingwang.cn
添加到下游的请求参数中添加响应头过滤器
spring:
cloud:
gateway:
routes:
- id: ribbon-client
uri: lb://ribbon-client
filters:
- AddResponseHeader=source, jinglingwang.cn
上面的示例会把
source=jinglingwang.cn
添加到所有匹配请求的下游响应头中。剔除重复的响应头过滤器
spring:
cloud:
gateway:
routes:
- id: ribbon-client
uri: lb://ribbon-client
filters:
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
DedupeResponseHeader过滤器也可接收可选策略参数,可接收参数值包括:RETAIN_FIRST (默认值,保留第一个值), RETAIN_LAST(保留最后一个值), and RETAIN_UNIQUE(保留所有唯一值,以它们第一次出现的顺序保留)。
开启Hystrix断路器功能的过滤器
要开启断路器功能,我们需要在pom.xml中添加Hystrix的相关依赖:spring-cloud-starter-netflix-hystrix
然后添加相关服务降级的处理类:
@RestController
public class FallbackController{
@GetMapping("/fallback")
public Object fallback() { Map<String,Object> result = new HashMap<>(3);
result.put("data","jinglingwang.cn");
result.put("message","Get request fallback!");
result.put("code",500);
return result;
}
}
添加配置
spring:
cloud:
gateway:
routes:
- id: eureka-provider
uri: lb://eureka-provider
predicates:
- Path=/api/ep/**
filters:
- StripPrefix=2
- name: Hystrix
args:
name: fallbackcmd
fallbackUri: forward:/fallback
启用resilience4j断路器的过滤器
要启用Spring Cloud断路器过滤器,需要引入依赖
spring-cloud-starter-circuitbreaker-reactor-resilience4j
spring:
cloud:
gateway:
routes:
- id: ribbon-client
uri: lb://ribbon-client
filters:
- CircuitBreaker=myCircuitBreaker
还可以接受一个可选的fallbackUri参数:
spring:
cloud:
gateway:
routes:
- id: eureka-provider
uri: lb://eureka-provider
predicates:
- Path=/api/ep/**
filters:
- StripPrefix=2
- name: CircuitBreaker
args:
name: myCircuitBreaker
fallbackUri: forward:/fallback
关闭eureka-provider服务,访问http://localhost:9000/api/ep/hello接口,出现降级处理信息
上面的配置也可以用JAVA Bean的方式配置:
@Bean
public RouteLocator customRoutes(RouteLocatorBuilder builder){
return builder.routes()
.route("eureka-provider", r -> r.path("/api/ep/**")
.filters(f->f.stripPrefix(2).circuitBreaker(c->c.setName("myCircuitBreaker").setFallbackUri("forward:/fallback")))
.uri("lb://eureka-provider"))
.build();
}
6.1 根据状态码使断路器跳闸
根据返回的状态码,决定断路器是否要跳闸
spring:
cloud:
gateway:
routes:
- id: eureka-provider
uri: lb://eureka-provider
predicates:
- Path=/api/ep/**
filters:
- StripPrefix=2
- name: CircuitBreaker
args:
name: myCircuitBreaker
fallbackUri: forward:/fallback
statusCodes:
- 500
- 'NOT_FOUND'
或者JAVA Bean配置:
@Bean
public RouteLocator customRoutes(RouteLocatorBuilder builder){
return builder.routes()
.route("eureka-provider", r -> r.path("/api/ep/**")
.filters(f->f.stripPrefix(2).circuitBreaker(c->c.setName("myCircuitBreaker").setFallbackUri("forward:/fallback").addStatusCode("500")))
.uri("lb://eureka-provider"))
.build();
}
其中
NOT_FOUND
是HttpStatus枚举的String表示形式增加路径的过滤器
spring:
cloud:
gateway:
routes:
- id: eureka-provider
uri: lb://eureka-provider
predicates:
- Path=/api/ep/**
filters:
- PrefixPath=/mypath
把
/mypath
作为所有匹配请求路径的前缀去掉路径前缀的过滤器
spring:
cloud:
gateway:
routes:
- id: eureka-provider
uri: lb://eureka-provider
predicates:
- Path=/api/ep/**
filters:
- StripPrefix=2
以上配置会忽略两位路径path,当访问网关API
/api/ep/hello
时,向eureka-provider发起/hello
请求用于限流的过滤器
RequestRateLimiter 过滤器可以用于限流,RateLimiter实现来确定是否允许继续当前请求。 如果不是,则返回HTTP 429—太多请求(默认)的状态。
该过滤器采用可选的
keyResolver
参数和速率限制器特定的参数,keyResolver是一个实现KeyResolver接口的bean。在配置中,使用SpEL按名称引用bean。#{@myKeyResolver}是引用名为myKeyResolver的bean的SpEL表达式。使用 Redis RateLimiter
引入redis依赖,配置好redis。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
添加配置,使用的算法是令牌桶算法。
spring:
cloud:
gateway:
routes:
- id: eureka-provider
uri: lb://eureka-provider
predicates:
- Path=/api/ep/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 #允许用户每秒处理多少个请求,而不丢弃任何请求。这是令牌桶的填充速率
redis-rate-limiter.burstCapacity: 20 #一个用户在一秒钟内允许做的最大请求数。这是令牌桶可以容纳的令牌数。将该值设置为零会阻止所有请求。
redis-rate-limiter.requestedTokens: 1 #一个请求花费多少令牌
通过在“replenishRate”和“burstCapacity”中设置相同的值来实现稳定的速率。通过将burstCapacity设置为高于replenishRate,可以允许临时爆发。
配置KeyResolver
JAVA 代码:
@Configuration
public class RedisRateLimiterConfig{
@Bean
KeyResolver userKeyResolver() {
// 根据请求参数中的phone进行限流
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("phone"));
}
@Bean
@Primary
public KeyResolver ipKeyResolver() {
// 根据访问IP进行限流
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
}
配置RequestRateLimiter
spring:
cloud:
gateway:
routes:
- id: eureka-provider
uri: lb://eureka-provider
predicates:
- Path=/api/ep/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1 #允许用户每秒处理多少个请求,而不丢弃任何请求。这是令牌桶的填充速率
redis-rate-limiter.burstCapacity: 2 #一个用户在一秒钟内允许做的最大请求数。这是令牌桶可以容纳的令牌数。将该值设置为零会阻止所有请求。
redis-rate-limiter.requestedTokens: 1 #一个请求花费多少令牌
key-resolver: "#{@ipKeyResolver}"
多次请求,会返回状态码为429的错误
用于重定向的过滤器
spring:
cloud:
gateway:
routes:
- id: eureka-provider
uri: lb://eureka-provider
predicates:
- Path=/api/ep/**
filters:
- StripPrefix=2
- RedirectTo=302, https://jinglingwang.cn #302 重定向到https://jinglingwang.cn
效果图如下:
用于重试的过滤器
spring:
cloud:
gateway:
routes:
- id: eureka-provider
uri: lb://eureka-provider
predicates:
- Path=/api/ep/**
filters:
- StripPrefix=2
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY
methods: GET,POST
backoff:
firstBackoff: 10ms
maxBackoff: 50ms
factor: 2
basedOnPreviousValue: false
参数解释:
- retries:应该尝试的重试次数。
- statuses:应该重试的HTTP状态代码,HttpStatus。
- methods:应该重试的HTTP方法,HttpMethod。
- series:要重试的状态码,Series。
- exceptions:应该重试的引发异常的列表。
- backoff:为重试配置的指数补偿
用于限制请求大小的过滤器
spring:
cloud:
gateway:
routes:
- id: eureka-provider
uri: lb://eureka-provider
predicates:
- Path=/api/ep/**
filters:
- StripPrefix=2
- name: RequestSize
args:
maxSize: 5MB
当请求大小大于允许的限制时,网关会限制请求到达下游服务。maxSize参数后跟一个可选的数据单位,如“KB节”或“MB”,默认是“B”。
上面的配置如果超过限制会出现以下提示:
errorMessage:Request size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0 MB
配置http超时时间
我们可以为所有路由配置Http超时(响应和连接),并且为每个特定路由配置单独的超时时间
全局的超时时间配置:
spring:
cloud:
gateway:
httpclient:
connect-timeout: 1000
response-timeout: 5s
特定路由配置超时时间
spring:
cloud:
gateway:
routes:
- id: eureka-provider
uri: lb://eureka-provider
predicates:
- Path=/api/ep/**
metadata:
response-timeout: 2000
connect-timeout: 1000
或者使用JAVA Bean的方式配置:
@Bean
public RouteLocator customRoutes(RouteLocatorBuilder builder){
return builder.routes()
.route("eureka-provider", r -> r.path("/api/ep/**")
.filters(f->f.stripPrefix(2)
.requestRateLimiter(rate->rate.setKeyResolver(ipKeyResolver))
.circuitBreaker(c->c.setName("myCircuitBreaker").setFallbackUri("forward:/fallback").addStatusCode("500").addStatusCode("NOT_FOUND")))
.uri("lb://eureka-provider")
.metadata(RESPONSE_TIMEOUT_ATTR, 200)
.metadata(CONNECT_TIMEOUT_ATTR, 200))
.build();
}
跨域配置
spring:
cloud:
gateway:
globalcors: # 全局跨域配置
cors-configurations:
'[/**]':
allowedOrigins: "jinglingwang.cn"
allowedMethods:
- GET
add-to-simple-url-handler-mapping: true
上面的配置,对于所有Get请求,允许来自jinglingwang.cn
的跨域请求。
自定义 Route Predicate Factories
通过一个名为AbstractRoutePredicateFactory
的抽象类来进行扩展,示例代码:
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {
public MyRoutePredicateFactory(){
super(Config.class);
}
@Override
public Predicate<ServerWebExchange> apply(Config config){
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange exchange) {
String host = exchange.getRequest().getHeaders().getFirst("Host");
return "jinglingwang.cn".equalsIgnoreCase(host);
}
@Override
public String toString() {
return String.format("host: name=%s ", config.host);
}
};
}
public static class Config {
//自定义过滤器的配置属性
@NotEmpty
private String host;
}
}
自定义 GatewayFilter Factories
要写GatewayFilter,必须实现GatewayFilterFactory,可以通过扩展一个名为AbstractGatewayFilterFactory的抽象类来进行。
@Component
public class AddHeaderGatewayFilterFactory extends AbstractGatewayFilterFactory<AddHeaderGatewayFilterFactory.Config>{
public AddHeaderGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config){
return (exchange, chain) -> {
// 如果要构建“前置”过滤器,则需要在调用chain.filter之前处理
ServerHttpRequest request = exchange.getRequest().mutate()
.header("source", "jinglingwang.cn").build();
//使用构建器来处理请求
return chain.filter(exchange.mutate().request(request).build());
};
}
public static class Config {
//Put the configuration properties for your filter here
}
}
配置属性
要查看所有与 Spring Cloud 网关相关的配置属性列表,请参见附录
⑥SpringCloud 实战:引入gateway组件,开启网关路由功能的更多相关文章
- ⑤SpringCloud 实战:引入Zuul组件,开启网关路由
这是SpringCloud实战系列中第4篇文章,了解前面第两篇文章更有助于更好理解本文内容: ①SpringCloud 实战:引入Eureka组件,完善服务治理 ②SpringCloud 实战:引入F ...
- ⑦SpringCloud 实战:引入Sleuth组件,完善服务链路跟踪
这是SpringCloud实战系列中第7篇文章,了解前面第两篇文章更有助于更好理解本文内容: ①SpringCloud 实战:引入Eureka组件,完善服务治理 ②SpringCloud 实战:引入F ...
- Linux 的路由功能
目录 文章目录 目录 前文列表 路由器 Router 路由 Routing 静态路由与动态路由 通过路由实现的全网通信示例 Linux 作为路由器 route 指令 路由表项的类型 ip route ...
- SpringCloud Gateway微服务网关实战与源码分析-上
概述 定义 Spring Cloud Gateway 官网地址 https://spring.io/projects/spring-cloud-gateway/ 最新版本3.1.3 Spring Cl ...
- 21.SpringCloud实战项目-后台题目类型功能(网关、跨域、路由问题一文搞定)
SpringCloud实战项目全套学习教程连载中 PassJava 学习教程 简介 PassJava-Learning项目是PassJava(佳必过)项目的学习教程.对架构.业务.技术要点进行讲解. ...
- ④SpringCloud 实战:引入Hystrix组件,分布式系统容错
这是SpringCloud实战系列中第4篇文章,了解前面第两篇文章更有助于更好理解本文内容: ①SpringCloud 实战:引入Eureka组件,完善服务治理 ②SpringCloud 实战:引入F ...
- ②SpringCloud 实战:引入Feign组件,完善服务间调用
这是SpringCloud实战系列中第二篇文章,了解前面第一篇文章更有助于更好理解本文内容: ①SpringCloud 实战:引入Eureka组件,完善服务治理 简介 Feign 是一个声明式的 RE ...
- 跟我学SpringCloud | 第十七篇:服务网关Zuul基于Apollo动态路由
目录 SpringCloud系列教程 | 第十七篇:服务网关Zuul基于Apollo动态路由 Apollo概述 Apollo相比于Spring Cloud Config优势 工程实战 示例代码 Spr ...
- 玩转SpringCloud(F版本) 四.路由网关(zuul)
本篇文章基于: 01)玩转SpringCloud 一.服务的注册与发现(Eureka) 02) 玩转SpringCloud 二.服务消费者(1)ribbon+restTemplate 03) 玩转Sp ...
随机推荐
- kali 更新msf
用leafpad打开,方便复制粘贴 leafpad /etc/apt/sources.list 然后复制下面的源覆盖原本的 deb http://mirrors.ustc.edu.cn/kali ka ...
- EasyRecovery扫描预览功能,助你选择需要的数据恢复
说到数据恢复,很多人都会选择EasyRecovery,EasyRecovery作为一个功能性还不错的数据恢复软件,能够帮你恢复丢失的数据以及重建文件系统. 在数据恢复的同时,EasyRecovery还 ...
- Mybatis是如何封装Jdbc的?
JDBC六个步骤 Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { //1. 加载驱动 C ...
- python中eval()和json.loads的区别
一.最近在写接口测试脚本时,发现当读取Excel用例时,有时候要用eval,有时候又要用json.loads,不知道区别,只能换一下就可以用了,不知道其中的原理,特地百度了下.于是就记录了下,以便后续 ...
- Elasticsearch 理解mapping中的store属性
默认情况下,对字段值进行索引以使其可搜索,但不存储它们 (store). 这意味着可以查询该字段,但是无法检索原始字段值.在这里我们必须理解的一点是: 如果一个字段的mapping中含有store属性 ...
- leetcode165. 比较版本号
比较两个版本号 version1 和 version2.如果 version1 > version2 返回 1,如果 version1 < version2 返回 -1, 除此之外返回 0 ...
- jquery删除文件
1 <div class="panel panel-default"> 2 <div class="panel-body"> 3 < ...
- Linux下使用Docker部署nacos-server(单机模式),丧心病狂的我在半夜给UCloud提交了一份工单
1. 拉取nacos-server镜像 进入 Docker Hub 查看nacos-server最新版本为 nacos-server:1.4.0 配置阿里云镜像加速 sudo mkdir -p /et ...
- CoProcessFunction实战三部曲之一:基本功能
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- 下载配置VNC
VNC通常使用连接图形化系统电脑可以安装了Gnome或者KDE yum autoremo ve tigervnc-server //移除 vncreboot //重启yum install tiger ...