像阿里云能力中台一样,我们输入阿里云的地址,阿里云内部的程序帮助我们进行转发到相应的服务去。
比如说阿里云的短信服务,他也是集成的若干个小服务,我们通过阿里云的地址进行访问时。阿里云再将具体的请求推送到具体的服务去。
 
 那么如何搭建网关进行请求的转发呢?
新建服务并设置断言

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);
        }
    }
}



















