为什么使用网关?
因为多个微服务的端口不同,前端调用不方便,使用网关可以统一接收处理前端的请求,同时方便接口的集中处理,比如鉴权、聚合接口文档、限流等等..
这里使用Knife4j文档工具来实现接口文档:Knife4j框架相关的blog | Knife4j
使用
- pom.xml引入依赖:
<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>
- 配置application.yml配置文件:
spring:cloud:gateway:routes:- id: backend-user-serviceuri: lb://backend-user-servicepredicates:- Path=/api/user/**- id: stuoj-backend-question-serviceuri: lb://backend-question-servicepredicates:- Path=/api/question/**- id: backend-comment-serviceuri: lb://backend-comment-servicepredicates:- Path=/api/comment/**- id: backend-xxx-serviceuri: lb://backend-xxx-servicepredicates:- Path=/api/xxx/**nacos:discovery:server-addr: localhost:8848application:name: backend-gatewaymain:web-application-type: reactive
server:port: 9090
聚合接口文档
目的:以一个全局的视角去集中管理里接口文档(Knife4j)
- 先给所有的服务引入依赖。同时开启接口文档配置
<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi2-spring-boot-starter</artifactId><version>4.3.0</version>
</dependency>
knife4j:enable: true
- 给网关服务配置集中管理文档
<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-gateway-spring-boot-starter</artifactId><version>4.3.0</version>
</dependency>
knife4j:gateway:# ① 第一个配置,开启gateway聚合组件enabled: true# ② 第二行配置,设置聚合模式采用discover服务发现的模式strategy: discoverdiscover:# ③ 第三行配置,开启discover模式enabled: true# ④ 第四行配置,聚合子服务全部为Swagger2规范的文档version: swagger2
之后就可以获得所有服务的文档了:
网关集中解决跨域
在gateway的模块下创建一个confg配置代码:
package com.stukk.stuojbackendgateway.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;import java.util.Arrays;/*** @Author: stukk* @Description: 跨域处理* @DateTime: 2023-12-07 19:04**/
@Configuration
public class CrosConfig {@Beanpublic CorsWebFilter corsWebFilter(){CorsConfiguration corsConfiguration = new CorsConfiguration();corsConfiguration.addAllowedMethod("*");corsConfiguration.setAllowCredentials(true);corsConfiguration.setAllowedOriginPatterns(Arrays.asList("*"));corsConfiguration.addAllowedHeader("*");UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());source.registerCorsConfiguration("/**",corsConfiguration);return new CorsWebFilter(source);}}
网关实现权限校验
使用拦截器Filter,拦截路径并判断权限
package com.stukk.stuojbackendgateway.filter;import cn.hutool.core.text.AntPathMatcher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
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.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.nio.charset.StandardCharsets;/*** @Author: stukk* @Description: 网关拦截器* @DateTime: 2023-12-07 19:16**/
@Component
public class GlobalAuthFilter implements GlobalFilter {private AntPathMatcher antPathMatcher = new AntPathMatcher();@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();String path = request.getURI().getPath();
// 判断是不是内部调用,拦截内部调用if(antPathMatcher.match("**/inner/**",path)){ServerHttpResponse response = exchange.getResponse();response.setStatusCode(HttpStatus.FORBIDDEN);DataBufferFactory dataBufferFactory = response.bufferFactory();DataBuffer dataBuffer = dataBufferFactory.wrap("无权限".getBytes(StandardCharsets.UTF_8));return response.writeWith(Mono.just(dataBuffer));}return chain.filter(exchange);}
}