像阿里云能力中台一样,我们输入阿里云的地址,阿里云内部的程序帮助我们进行转发到相应的服务去。
比如说阿里云的短信服务,他也是集成的若干个小服务,我们通过阿里云的地址进行访问时。阿里云再将具体的请求推送到具体的服务去。
那么如何搭建网关进行请求的转发呢?
新建服务并设置断言
spring:
application:
name: usersystem-apigateway
cloud:
gateway:
discovery:
locator:
lowerCaseServiceId: true
enabled: true
routes:
- id: api-gateway
uri: lb://usersystem-apigateway
predicates:
- Path=/**
filters:
- PathRedirect
编写拦截器
编写PathRedirectGatewayFilterFactory
package com.zxl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;
/**
* API路径转发为真实服务地址
*/
@Component
public class PathRedirectGatewayFilterFactory extends AbstractGatewayFilterFactory {
@Autowired
private GateWayWebClient webClient;
@Override
public GatewayFilter apply (Object config){
return (exchange, chain) -> webClient.send(exchange);
}
}
编写实现方法
package com.zxl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Map;
import java.util.Objects;
import static com.zxl.CommonUtil.requireHttpBody;
import static com.zxl.Constant.*;
/**
* @author lancer
*/
@Service
@Slf4j
public class GateWayWebClient {
@Resource
private WebClient webClient;
/**
* 发送请求
*/
public Mono<Void> send(ServerWebExchange exchange){
ServerHttpRequest frontEndReq = exchange.getRequest();
ServerHttpResponse frontEndResp = exchange.getResponse();
String path = frontEndReq.getPath().pathWithinApplication().value();
HttpMethod httpMethod = frontEndReq.getMethod();
Map<String, Object> attributes = exchange.getAttributes();
//后端真实服务的信息
ApiDetailDTO apiDetail = new ApiDetailDTO();
apiDetail.setServerInfo("127.0.0.1:9000");
apiDetail.setPath("/base/sendMessage2");
apiDetail.setProtocol("http");
attributes.put(API_DETAIL, apiDetail);
//后端真实服务的地址
String requrl = getRealUrl(apiDetail);
String relpath = apiDetail.getPath();
//服务超时时间
long timeout = 600;
long timeOut = apiDetail.getTimeout() == null ? timeout : apiDetail.getTimeout();
String param = frontEndReq.getURI().getQuery();
//拼接query查询参数
String url = requrl.concat(relpath) + (StringUtils.isEmpty(param) ? "" :"?"+param);
log.info("req url is: {}, final url is: {}", requrl, url);
//调用后端服务
WebClient.RequestBodySpec reqBodySpec = webClient.method(httpMethod).
uri(url).
headers(httpHeaders -> {
httpHeaders.addAll(frontEndReq.getHeaders());
httpHeaders.remove("HOST");
});
WebClient.RequestHeadersSpec<?> reqHeadersSpec;
if (requireHttpBody(httpMethod)) {
reqHeadersSpec = reqBodySpec.body(BodyInserters.fromDataBuffers(frontEndReq.getBody()));
} else {
reqHeadersSpec = reqBodySpec;
if (Objects.nonNull(param)) {
attributes.put(REQ_PARAMS, param);
}
}
//调用后端服务
Mono<ClientResponse> clientResponse = reqHeadersSpec
.exchange()
.timeout(Duration.ofSeconds(timeOut))
.onErrorResume(ex ->
frontEndResp.writeWith(Mono.error(ex)).then(Mono.empty())
);
Mono<Void> body = clientResponse.flatMap(cr->{
Mono<Void> mono = frontEndResp.writeWith(DataBufferUtils.join(cr.bodyToFlux(DataBuffer.class))
.doOnNext(dataBuffer -> {
String respBody = dataBuffer.toString(StandardCharsets.UTF_8);
attributes.put(RESP_MSG, respBody.replaceAll(SPECIAL_SYMBOL, BLANK_STR));
}));
frontEndResp.setStatusCode(cr.statusCode());
frontEndResp.getHeaders().putAll(cr.headers().asHttpHeaders());
return mono;
});
return body;
}
/**
* 根据不同环境获取不同的url地址
* * @param dto
*/
private String getRealUrl(ApiDetailDTO apiDetail){
String serviceUrl = apiDetail.getServerInfo();
String protocol = apiDetail.getProtocol();
if (serviceUrl.startsWith(HTTP_PROTOCOL) || serviceUrl.startsWith(HTTPS_PROTOCOL)) {
return serviceUrl;
} else {
return protocol.concat(PROTOCOL_CONNECTOR).concat(serviceUrl);
}
}
}