All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.noear.solon.cloud.gateway.CloudRouteHandlerDefault Maven / Gradle / Ivy

There is a newer version: 3.0.5-M3
Show newest version
/*
 * Copyright 2017-2024 noear.org and authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.noear.solon.cloud.gateway;

import io.vertx.core.AsyncResult;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpMethod;
import io.vertx.ext.web.client.HttpRequest;
import io.vertx.ext.web.client.HttpResponse;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
import org.noear.solon.Solon;
import org.noear.solon.cloud.gateway.exchange.ExContext;
import org.noear.solon.rx.Completable;
import org.noear.solon.rx.CompletableEmitter;
import org.noear.solon.core.LoadBalance;
import org.noear.solon.core.exception.StatusException;
import org.noear.solon.util.KeyValues;

import java.net.URI;
import java.util.Map;

/**
 * 分布式路由处理器默认实现
 *
 * @author noear
 * @since 2.9
 */
public class CloudRouteHandlerDefault implements CloudRouteHandler {
    private WebClient httpClient;

    public CloudRouteHandlerDefault() {
        Solon.context().getBeanAsync(Vertx.class, b -> {
            WebClientOptions options = new WebClientOptions()
                    .setMaxPoolSize(250)
                    .setConnectTimeout(1000 * 3) // milliseconds: 5s
                    .setIdleTimeout(60) // seconds: 60s
                    .setKeepAlive(true)
                    .setKeepAliveTimeout(60); // seconds: 60s

            this.httpClient = WebClient.create(b, options);
        });
    }

    /**
     * 处理
     */
    @Override
    public Completable handle(ExContext ctx) {
        try {
            //构建请求
            HttpRequest req1 = buildHttpRequest(ctx);

            //构建超时
            if (ctx.timeout() != null) {
                req1.connectTimeout(ctx.timeout().getConnectTimeout() * 1000);
                req1.timeout(ctx.timeout().getResponseTimeout() * 1000);
            }

            //同步 header
            for (KeyValues kv : ctx.newRequest().getHeaders().values()) {
                req1.putHeader(kv.getKey(), kv.getValues());
            }

            return Completable.create(emitter -> {
                //异步 执行
                //同步 body(流复制)
                if ("GET".equals(ctx.newRequest().getMethod())) {
                    req1.send(ar -> {
                        callbackHandle(ctx, ar, emitter);
                    });
                } else {
                    ctx.newRequest().getBody().onComplete(ar1 -> {
                        if (ar1.succeeded()) {
                            req1.sendBuffer(ar1.result(), ar2 -> {
                                callbackHandle(ctx, ar2, emitter);
                            });
                        } else {
                            emitter.onError(new StatusException(ar1.cause(), 400));
                        }
                    });
                }
            });
        } catch (Throwable ex) {
            //如查出错,说明客户端发的数据有问题
            if (ex instanceof StatusException) {
                return Completable.error(ex);
            } else {
                return Completable.error(new StatusException(ex, 400));
            }
        }
    }

    /**
     * 构建 http 请求对象
     */
    private HttpRequest buildHttpRequest(ExContext ctx) {
        URI targetUri;
        if (LoadBalance.URI_SCHEME.equals(ctx.target().getScheme())) {
            String tmp = LoadBalance.get(ctx.target().getHost()).getServer(ctx.target().getPort());
            if (tmp == null) {
                throw new StatusException("The target service does not exist", 404);
            }

            targetUri = URI.create(tmp);
        } else {
            targetUri = ctx.target();
        }

        if (targetUri.getPort() > 0) {
            return httpClient.request(HttpMethod.valueOf(ctx.newRequest().getMethod()),
                    targetUri.getPort(),
                    targetUri.getHost(),
                    ctx.newRequest().getPathAndQueryString());
        } else {
            return httpClient.request(HttpMethod.valueOf(ctx.newRequest().getMethod()),
                    targetUri.getHost(),
                    ctx.newRequest().getPathAndQueryString());
        }
    }

    /**
     * 请求回调处理
     */
    private void callbackHandle(ExContext ctx, AsyncResult> ar, CompletableEmitter subscriber) {
        try {
            if (ar.succeeded()) {
                HttpResponse resp1 = ar.result();

                //code
                ctx.newResponse().status(resp1.statusCode());
                //header
                for (Map.Entry kv : resp1.headers()) {
                    ctx.newResponse().headerAdd(kv.getKey(), kv.getValue());
                }
                //body 输出(流复制) //有可能网络已关闭
                ctx.newResponse().body(resp1.body());

                subscriber.onComplete();
            } else {
                subscriber.onError(ar.cause());
            }
        } catch (Throwable ex) {
            subscriber.onError(ex);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy