spring-cloud-starter-gateway 转发请求并返回结果
1、添加依赖
<!-- nacos: 服务注册与发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
<!--网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
2、去yml文件配置相关信息
server:
port: 9000
spring:
application:
name: gateway-server
main:
allow-bean-definition-overriding: true
cloud:
nacos:
discovery:
server-addr: 192.168.1.12:8848
namespace: 612f03a9-624d-4109-9f9a-b8c79a7082fa #创建的命名空间,非必选
gateway:
httpclient:
connect-timeout: 5000
response-timeout: 10s
routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
- id: provider-route # 当前路由的标识, 要求唯一,可以随便写
uri: lb://service-provider # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
predicates: # 断言(就是路由转发要满足的条件)
- Path=/provider/** # 当请求路径满足Path指定的规则时,才进行路由转发
filters: # 过滤器,请求在传递过程中可以通过过滤器对其进行一定的修改
- StripPrefix=1 # 转发之前去掉1层路径
- id: consumer-route
uri: lb://service-consumer
predicates:
- Path=/consumer/**
filters:
- StripPrefix=1
#消息微服务
- id: message-route
uri: lb://service-message
predicates:
- Path=/message/**
filters:
- StripPrefix=1
3、配置跨域
可以在yml文件配置或者代码配置,这里用的是代码
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;
/**
* @author czw
* @version 1.0
* @describe: 解决跨域问题
* @date 2022/02/15 17:55:23
*/
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.setAllowCredentials(true);
// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
corsConfiguration.setMaxAge(18000L);
source.registerCorsConfiguration("/**",corsConfiguration);
return new CorsWebFilter(source);
}
}
4、获取nacos服务返回的信息
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
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.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* @author czw
* @version 1.0
* @describe:
* @date 2022/02/16 09:18:18
*/
@Component
@Slf4j
public class ResponseFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//获取返回的response
ServerHttpResponse originalResponse = exchange.getResponse();
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
HttpStatus statusCode = originalResponse.getStatusCode();
if (statusCode ==HttpStatus.OK){
ServerHttpResponseDecorator decorator = new ServerHttpResponseDecorator(originalResponse){
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body){
Flux<? extends DataBuffer> fluxBody = Flux.from(body);
return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
DataBuffer join = dataBufferFactory.join(dataBuffers);
byte[] content = new byte[join.readableByteCount()];
join.read(content);
DataBufferUtils.release(join);
String responseData = new String(content, StandardCharsets.UTF_8);
log.info("响应内容:{}", responseData);
byte[] uppedContent = new String(responseData.getBytes(), Charset.forName("UTF-8")).getBytes();
return bufferFactory.wrap(uppedContent);
}));
}
};
return chain.filter(exchange.mutate().response(decorator).build());
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
//值越小优先级越高
return -2;
}
}
5、处理返回响应头
缺少这个前端会获取不到返回值,但接口请求返回正常
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
/**
* @author czw
* @version 1.0
* @describe: 处理返回响应头
* @date 2022/02/16 11:43:18
*/
@Component("DistinctHeaderGlobalFilter")
public class DistinctHeaderGlobalFilter implements GlobalFilter, Ordered {
@Override
public int getOrder() {
// 指定此过滤器位于NettyWriteResponseFilter之后
// 即待处理完响应体后接着处理响应头
return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + 1;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return chain.filter(exchange).then(Mono.defer(() -> {
exchange.getResponse().getHeaders().entrySet().stream()
.filter(kv -> (kv.getValue() != null && kv.getValue().size() > 1))
.filter(kv -> (kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)
|| kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)))
.forEach(kv -> kv.setValue(new ArrayList<String>() {{
add(kv.getValue().get(0));
}}));
return chain.filter(exchange);
}));
}
}
效果图