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插件的正常使用。
    不然给用户的感觉是会莫名其妙的问题。

  • 相关阅读:
    Binary Tree Zigzag Level Order Traversal
    Binary Tree Level Order Traversal
    Symmetric Tree
    Best Time to Buy and Sell Stock II
    Best Time to Buy and Sell Stock
    Triangle
    Populating Next Right Pointers in Each Node II
    Pascal's Triangle II
    Pascal's Triangle
    Populating Next Right Pointers in Each Node
  • 原文地址:https://www.cnblogs.com/zendwang/p/14690428.html
Copyright © 2011-2022 走看看