|
|
@@ -0,0 +1,111 @@
|
|
|
+/*
|
|
|
+ * Copyright (c) 2018-2025, hnqz All rights reserved.
|
|
|
+ *
|
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
|
+ * modification, are permitted provided that the following conditions are met:
|
|
|
+ *
|
|
|
+ * Redistributions of source code must retain the above copyright notice,
|
|
|
+ * this list of conditions and the following disclaimer.
|
|
|
+ * Redistributions in binary form must reproduce the above copyright
|
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
|
+ * Neither the name of the pig4cloud.com developer nor the names of its
|
|
|
+ * contributors may be used to endorse or promote products derived from
|
|
|
+ * this software without specific prior written permission.
|
|
|
+ * Author: hnqz
|
|
|
+ */
|
|
|
+
|
|
|
+package net.yyc.common.gray.nacos;
|
|
|
+
|
|
|
+import java.util.Optional;
|
|
|
+
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Nacos 跨 Group 服务名 {@code group@@service} 与 URI 合法 host 之间的编解码。
|
|
|
+ * <p>
|
|
|
+ * Java {@link java.net.URI} 的 host 不允许 {@code @}、{@code _} 等字符,网关路由 URI 使用
|
|
|
+ * {@code group--service}(group 中下划线转为连字符)存储,负载均衡前再还原为 Nacos serviceId。
|
|
|
+ * <p>
|
|
|
+ * 当路由通过 Spring 标准 {@code PropertiesRouteDefinitionLocator} 加载时,{@code @@} 会被
|
|
|
+ * Java URI 解析器 URL 编码为 {@code %40%40},本类同时处理这两种格式。
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+public final class NacosGroupServiceIdCodec {
|
|
|
+
|
|
|
+ private static final String NACOS_GROUP_SERVICE_SEPARATOR = "@@";
|
|
|
+
|
|
|
+ private static final String URI_GROUP_SERVICE_SEPARATOR = "--";
|
|
|
+
|
|
|
+ private static final String URL_ENCODED_SEPARATOR = "%40%40";
|
|
|
+
|
|
|
+ private NacosGroupServiceIdCodec() {
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将 Nacos 跨 group URI 编码为 URI 合法格式。
|
|
|
+ * <ul>
|
|
|
+ * <li>{@code lb://cso_hnqz@@hnqz-auth} → {@code lb://cso-hnqz--hnqz-auth}</li>
|
|
|
+ * <li>{@code lb://cso_hnqz%40%40hnqz-auth} → {@code lb://cso-hnqz--hnqz-auth}</li>
|
|
|
+ * </ul>
|
|
|
+ */
|
|
|
+ public static String encodeLbUri(String uri) {
|
|
|
+ if (uri == null || !uri.startsWith("lb://")) {
|
|
|
+ return uri;
|
|
|
+ }
|
|
|
+ String hostPart = uri.substring("lb://".length());
|
|
|
+ if (hostPart.isEmpty()) {
|
|
|
+ return uri;
|
|
|
+ }
|
|
|
+
|
|
|
+ String working = hostPart;
|
|
|
+ if (working.contains(URL_ENCODED_SEPARATOR)) {
|
|
|
+ working = working.replace(URL_ENCODED_SEPARATOR, NACOS_GROUP_SERVICE_SEPARATOR);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!working.contains(NACOS_GROUP_SERVICE_SEPARATOR)) {
|
|
|
+ return uri;
|
|
|
+ }
|
|
|
+
|
|
|
+ int sep = working.indexOf(NACOS_GROUP_SERVICE_SEPARATOR);
|
|
|
+ String group = working.substring(0, sep).replace('_', '-');
|
|
|
+ String service = working.substring(sep + NACOS_GROUP_SERVICE_SEPARATOR.length());
|
|
|
+ String encoded = "lb://" + group + URI_GROUP_SERVICE_SEPARATOR + service;
|
|
|
+ log.debug("[跨Group编解码] URI 编码: {} → {}", uri, encoded);
|
|
|
+ return encoded;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * {@code cso-hnqz--hnqz-auth} → {@code cso_hnqz@@hnqz-auth}
|
|
|
+ */
|
|
|
+ public static String decodeServiceId(String uriHost) {
|
|
|
+ return parseFromUriHost(uriHost).map(gs -> gs.getGroup() + NACOS_GROUP_SERVICE_SEPARATOR + gs.getServiceName())
|
|
|
+ .orElse(uriHost);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从 URI host({@code cso-hnqz--hnqz-auth})解析 group 与 serviceName。
|
|
|
+ */
|
|
|
+ public static Optional<NacosGroupService> parseFromUriHost(String uriHost) {
|
|
|
+ if (uriHost == null || !uriHost.contains(URI_GROUP_SERVICE_SEPARATOR)) {
|
|
|
+ return Optional.empty();
|
|
|
+ }
|
|
|
+ int sep = uriHost.indexOf(URI_GROUP_SERVICE_SEPARATOR);
|
|
|
+ String group = uriHost.substring(0, sep).replace('-', '_');
|
|
|
+ String serviceName = uriHost.substring(sep + URI_GROUP_SERVICE_SEPARATOR.length());
|
|
|
+ return Optional.of(new NacosGroupService(group, serviceName));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从 Nacos serviceId({@code cso_hnqz@@hnqz-auth})解析 group 与 serviceName。
|
|
|
+ */
|
|
|
+ public static Optional<NacosGroupService> parseFromNacosServiceId(String nacosServiceId) {
|
|
|
+ if (nacosServiceId == null || !nacosServiceId.contains(NACOS_GROUP_SERVICE_SEPARATOR)) {
|
|
|
+ return Optional.empty();
|
|
|
+ }
|
|
|
+ int sep = nacosServiceId.indexOf(NACOS_GROUP_SERVICE_SEPARATOR);
|
|
|
+ return Optional.of(new NacosGroupService(nacosServiceId.substring(0, sep),
|
|
|
+ nacosServiceId.substring(sep + NACOS_GROUP_SERVICE_SEPARATOR.length())));
|
|
|
+ }
|
|
|
+
|
|
|
+}
|