404008945 opened a new issue, #10393:
URL: https://github.com/apache/dubbo/issues/10393

   <!-- If you need to report a security issue please visit 
https://github.com/apache/dubbo/security/policy -->
   
   - [x] I have searched the [issues](https://github.com/apache/dubbo/issues) 
of this repository and believe that this is not a duplicate.
   
   ### Environment
   
   * Dubbo version: 2.7.6及以后
   * Operating System version: windows 10
   * Java version: 1.8
   
   ### Steps to reproduce this issue
   
   1. 生产者和消费者服务地址url的group,version为空
   2. 先启动生产者,服务正常注册到注册中心
   3. 启动消费者,可能导致服务调用 报错No provider
   
   
   ### Expected Behavior
   
   <!-- What do you expect from the above steps?-->
   服务正常调用
   
   ### Actual Behavior
   
   <!-- What actually happens? -->
   
   
   org.apache.dubbo.registry.integration.DynamicDirectory#doList
   
   
   ```
      throw new RpcException(RpcException.FORBIDDEN_EXCEPTION, "No provider 
available from registry " +
                       getUrl().getAddress() + " for service " + 
getConsumerUrl().getServiceKey() + " on consumer " +
                       NetUtils.getLocalHost() + " use dubbo version " + 
Version.getVersion() +
                       ", please check status of providers(disabled, not 
registered or in blacklist).");
   ```
   
   
   ### My suggestion
   org.apache.dubbo.registry.nacos.NacosRegistry#getServiceNames0
   ```java
    private Set<String> getServiceNames0(URL url) {
           NacosServiceName serviceName = createServiceName(url);
   
           final Set<String> serviceNames;
   
           if (serviceName.isConcrete()) { // is the concrete service name
               serviceNames = new LinkedHashSet<>();
               serviceNames.add(serviceName.toString());
               // Add the legacy service name since 2.7.6
               String legacySubscribedServiceName = 
getLegacySubscribedServiceName(url);
               if (!serviceName.toString().equals(legacySubscribedServiceName)) 
{
                   //avoid duplicated service names
                   serviceNames.add(legacySubscribedServiceName);
               }
           } else {
               serviceNames = filterServiceNames(serviceName);
           }
   
           return serviceNames;
       }
   ```
   2.7.6及以后生成规则
   ```java
   public NacosServiceName(URL url) {
           serviceInterface = url.getParameter(INTERFACE_KEY);
           category = isConcrete(serviceInterface) ? DEFAULT_CATEGORY : 
url.getParameter(CATEGORY_KEY);
           version = url.getParameter(VERSION_KEY, DEFAULT_PARAM_VALUE);
           group = url.getParameter(GROUP_KEY, DEFAULT_PARAM_VALUE);
           value = toValue();
       }
   private String toValue() {
           return category +
                   NAME_SEPARATOR + serviceInterface +
                   NAME_SEPARATOR + version +
                   NAME_SEPARATOR + group;
       }
   ```
   getLegacySubscribedServiceName生成规则
   ```java
    /**
        * Get the legacy subscribed service name for compatible with Dubbo 
2.7.3 and below
        *
        * @param url {@link URL}
        * @return non-null
        * @since 2.7.6
        */ 
   private String getLegacySubscribedServiceName(URL url) {
           StringBuilder serviceNameBuilder = new 
StringBuilder(DEFAULT_CATEGORY);
           appendIfPresent(serviceNameBuilder, url, INTERFACE_KEY);
           appendIfPresent(serviceNameBuilder, url, VERSION_KEY);
           appendIfPresent(serviceNameBuilder, url, GROUP_KEY);
           return serviceNameBuilder.toString();
       }
      private void appendIfPresent(StringBuilder target, URL url, String 
parameterName) {
           String parameterValue = url.getParameter(parameterName);
           if (!StringUtils.isBlank(parameterValue)) {
               target.append(SERVICE_NAME_SEPARATOR).append(parameterValue);
           }
       }
   ```
   
2.7.6版本之后生成的serviceName,即使group,version为空也不会省略间隔符NAME_SEPARATOR,而getLegacySubscribedServiceName方法中,如果group,version为空会省略冒号,也就是说serviceName和legacySubscribedServiceName在应该相等的情况下,也因为NAME_SEPARATOR被判断为了不相等,重复添加了,legacySubscribedServiceName也作为服务名。那么就会有两个服务名形如
   provider:com.xishan.store.usercenter.userapi.facade.XXReadFacade::
   provider:com.xishan.store.usercenter.userapi.facade.XXReadFacade
   
   
生产者也使用的2.7.6后的版本,那么注册中心只会有provider:com.xishan.store.usercenter.userapi.facade.XXReadFacade::
   而
   provider:com.xishan.store.usercenter.userapi.facade.XXReadFacade是不存在的
   
   那么如果如果兼容旧版的legacySubscribedServiceName晚于实际存在的服务名进入
   org.apache.dubbo.registry.integration.RegistryDirectory#refreshInvoker
   ```java
        private void refreshInvoker(List<URL> invokerUrls) {
           Assert.notNull(invokerUrls, "invokerUrls should not be null");
   
           if (invokerUrls.size() == 1
                   && invokerUrls.get(0) != null
                   && EMPTY_PROTOCOL.equals(invokerUrls.get(0).getProtocol())) {
               this.forbidden = true; // Forbid to access
               this.invokers = Collections.emptyList();
               routerChain.setInvokers(this.invokers);
               destroyAllInvokers(); // Close all invokers
           } else {
              
               this.forbidden = false; // Allow to access
               ····省略代码····
   
           }
   
           // notify invokers refreshed
           this.invokersChanged();
       }
   
   ```
   导致invoker被清空,forbidden设置为true,当我们要使用dubbo服务时,报出no Provider


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to