zoukankan      html  css  js  c++  java
  • 运行 soul-examlpes-http 实例遇到的问题

    前置条件

    1. 从github下载代码网关后端项目soul、网关前端项目soul-dashboard
    2. 本地安装好mysql、zookeeper并启动
    3. 前端项目编译需要nodejs,npm
    4. 启动soul-admin 管理端
    5. 启动soul-bootstrap 网关
    6. 启动 soul-examlpes-http 实例项目
    7. 运行前端项目,打开浏览器输入 http://localhost:8000/

    测试项目

    1. 测试实例项目返回正常
    http://127.0.0.1:8189/order/path/1/sdsd
    zend-deMacBook-Pro:bin zend$ curl http://127.0.0.1:8189/order/path/1/sdsd
    {"id":"1","name":"hello world restful: sdsd"}
    
    1. 测试通过网关访问实例项目
    curl http://localhost:9195/http/order/path/1/sdsd
    {"timestamp":"2021-04-22T07:40:29.168+0000","path":"/http/order/path/1/sdsd","status":404,"error":"Not Found","message":null,"requestId":"3f41230f"}
    

    经过观察日志发现

    2021-04-22 14:55:39 [soul-work-threads-5] INFO  org.dromara.soul.plugin.base.AbstractSoulPlugin - divide rule success match , rule name :/http/order/path/**
    2021-04-22 14:55:39 [soul-work-threads-5] INFO  org.dromara.soul.plugin.httpclient.WebClientPlugin - The request urlPath is http://127.0.0.1:8189/http/order/path/1/sdsd, retryTimes is 0
    

    实际上正常应该转发到这个后端地址http://127.0.0.1:8189/order/path/1/sdsd
    应该是经过DividePlugin插件做负载均衡, 然后是WebClientPlugin插件做http请求调用;
    应该是这一块的问题DividePlugin.java

    @Slf4j
    public class DividePlugin extends AbstractSoulPlugin {
    
        @Override
        protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
            final SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT);
            .....
            // set the http url
            String domain = buildDomain(divideUpstream);
         **   String realURL = buildRealURL(domain, soulContext, exchange);**
            exchange.getAttributes().put(Constants.HTTP_URL, realURL);
            ....
        }
    ....
        private String buildRealURL(final String domain, final SoulContext soulContext, final ServerWebExchange exchange) {
            String path = domain;
            final String rewriteURI = (String) exchange.getAttributes().get(Constants.REWRITE_URI);
            if (StringUtils.isNoneBlank(rewriteURI)) {
                path = path + rewriteURI;
            } else {
                final String realUrl = soulContext.getRealUrl();
               if (StringUtils.isNoneBlank(realUrl)) {
                    path = path + realUrl;
                }
            }
            String query = exchange.getRequest().getURI().getRawQuery();
            if (StringUtils.isNoneBlank(query)) {
                return path + "?" + query;
            }
            return path;
        }
    }
    
    

    应该是buildRealURL方法这一块的问题,经过调试发现realUrl为/http/order/path/1/sdsd;
    再查是哪里设置的realUrl?
    在 GlobalPlugin插件中配置的 builder.build(exchange)中配置的soulContext
    GlobalPlugin.java

    public class GlobalPlugin implements SoulPlugin {
         private final SoulContextBuilder builder;
        @Override
        public Mono<Void> execute(final ServerWebExchange exchange, final SoulPluginChain chain) {
           ...
            SoulContext soulContext;
            if (StringUtils.isBlank(upgrade) || !"websocket".equals(upgrade)) {
                soulContext = builder.build(exchange);
            } else {
                final MultiValueMap<String, String> queryParams = request.getQueryParams();
                soulContext = transformMap(queryParams);
            }
            exchange.getAttributes().put(Constants.CONTEXT, soulContext);
            return chain.execute(exchange);
        }
        ....
    }
    

    最终调用DefaultSoulContextBuilder类中builder方法

    public class DefaultSoulContextBuilder implements SoulContextBuilder {
        
        private final Map<String, SoulContextDecorator> decoratorMap;
         ......
    
        @Override
        public SoulContext build(final ServerWebExchange exchange) {
            ServerHttpRequest request = exchange.getRequest();
            String path = request.getURI().getPath();
            MetaData metaData = MetaDataCache.getInstance().obtain(path);
            if (Objects.nonNull(metaData) && metaData.getEnabled()) {
                exchange.getAttributes().put(Constants.META_DATA, metaData);
            }
            return Optional.ofNullable(metaData).map(e -> decoratorMap.get(e.getRpcType()))
                    .orElse(decoratorMap.get(RpcTypeEnum.HTTP.getName()))
                    .decorator(buildDefault(request), metaData);
        }
        
        private SoulContext buildDefault(final ServerHttpRequest request) {
            String appKey = request.getHeaders().getFirst(Constants.APP_KEY);
            String sign = request.getHeaders().getFirst(Constants.SIGN);
            String timestamp = request.getHeaders().getFirst(Constants.TIMESTAMP);
            SoulContext soulContext = new SoulContext();
            String path = request.getURI().getPath();
            soulContext.setPath(path);
            soulContext.setAppKey(appKey);
            soulContext.setSign(sign);
            soulContext.setTimestamp(timestamp);
            soulContext.setStartDateTime(LocalDateTime.now());
            Optional.ofNullable(request.getMethod()).ifPresent(httpMethod -> soulContext.setHttpMethod(httpMethod.name()));
            return soulContext;
        }
    }
    

    又使用类DivideSoulContextDecorator去完善soulContext里部分属性字段

    public class DivideSoulContextDecorator implements SoulContextDecorator {
        
        @Override
        public SoulContext decorator(final SoulContext soulContext, final MetaData metaData) {
            String path = soulContext.getPath();
            soulContext.setMethod(path);
            soulContext.setRealUrl(path);
            soulContext.setRpcType(RpcTypeEnum.HTTP.getName());
            return soulContext;
        }
    }
    

    realUrl 就是在这里设置的

    继续搜索 发现ContextPathMappingPlugin类里也有对realUrl的处理

    public class ContextPathMappingPlugin extends AbstractSoulPlugin {
    
        @Override
        protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
            final SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT);
            assert soulContext != null;
            final String handle = rule.getHandle();
            final ContextMappingHandle contextMappingHandle = GsonUtils.getInstance().fromJson(handle, ContextMappingHandle.class);
            if (Objects.isNull(contextMappingHandle) || StringUtils.isBlank(contextMappingHandle.getContextPath())) {
                log.error("context path mapping rule configuration is null :{}", rule);
                return chain.execute(exchange);
            }
            this.buildContextPath(soulContext, contextMappingHandle);
            return chain.execute(exchange);
        }
        ...
    
        /**
         * Build the context path and realUrl.
         *
         * @param context context
         * @param handle  handle
         */
        private void buildContextPath(final SoulContext context, final ContextMappingHandle handle) {
            context.setContextPath(handle.getContextPath());
            context.setModule(handle.getContextPath());
            if (!StringUtils.isBlank(handle.getRealUrl())) {
                log.info("context path mappingPlugin replaced old :{} , real:{}", context.getRealUrl(), handle.getRealUrl());
                context.setRealUrl(handle.getRealUrl());
                return;
            }
            String realUrl = context.getPath().substring(handle.getContextPath().length());
            context.setRealUrl(realUrl);
        }
    }
    

    去官网了解一下这个插件发现
    soul网关在对目标服务调用的时候,还容许用户使用 context_path 插件来重写请求路径的contextPath,
    还要求用divide插件时必须要开启context_path插件;

    再去管理台查一下这个插件是否开启,发现被我手抖给关闭了,
    开启该插件后,再去试试看,一切正常。

    我觉得用户体验不好,关闭context_path插件要提醒一下 用户,关闭了会影响divide插件的正常使用。
    不然给用户的感觉是会莫名其妙的问题。

  • 相关阅读:
    P1909 买铅笔
    树形结构
    图片
    cookie
    JSON
    操作数组
    竖线分割|
    订单提交中... 后前面三点动画
    w'w
    解决扫码枪输入input时受中文输入法的影响
  • 原文地址:https://www.cnblogs.com/zendwang/p/14690428.html
Copyright © 2011-2022 走看看