com.huawei.discovery.utils.RequestInterceptorUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of springboot-registry-plugin Show documentation
Show all versions of springboot-registry-plugin Show documentation
The plugin module of registry from springboot
/*
* Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved.
*
* 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
*
* http://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 com.huawei.discovery.utils;
import com.huawei.discovery.entity.ServiceInstance;
import com.huawei.discovery.entity.SimpleRequestRecorder;
import com.huawei.discovery.retry.InvokerContext;
import com.huaweicloud.sermant.core.common.LoggerFactory;
import com.huaweicloud.sermant.core.plugin.agent.entity.ExecuteContext;
import com.huaweicloud.sermant.core.utils.StringUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.StringTokenizer;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* 解析url参数、构建公共方法相关工具类
*
* @author chengyouling
* @since 2022-10-09
*/
public class RequestInterceptorUtils {
private static final Logger LOGGER = LoggerFactory.getLogger();
private static final SimpleRequestRecorder RECORDER = new SimpleRequestRecorder();
private static final int URL_INFO_INIT_SIZE = 8;
/**
* 解析url时,分隔的最小长度, 其path必须为/serviceName/api/xxx, 否则将不是目标请求 {@link RequestInterceptorUtils#recoverUrl(URL)}
*/
private static final int MIN_LEN_FOR_VALID_PATH = 2;
/**
* 解析url时,分隔的最小长度, 其url必须为http:/www.domain.com/serviceName/api/xxx, 否则将不是目标请求
* {@link RequestInterceptorUtils#recoverUrl(String)}
*/
private static final int MIN_LEN_FOR_VALID_URL = 4;
private RequestInterceptorUtils() {
}
private static String formatPath(String path, String query) {
if (query != null) {
return path + "?" + query;
}
return path;
}
/**
* 解析url参数信息 http://www.domain.com/serviceName/sayHello?name=1
*
* @param url url地址
* @return url解析后的主机名、路径
*/
public static Map recoverUrl(URL url) {
if (url == null) {
return Collections.emptyMap();
}
final String protocol = url.getProtocol();
// /serviceName/sayHello?name=1, 已切分为serviceName, sayHello?name=1
String delim = String.valueOf(HttpConstants.HTTP_URL_SINGLE_SLASH);
final StringTokenizer tokenizer = new StringTokenizer(url.getPath(), delim);
if (tokenizer.countTokens() < MIN_LEN_FOR_VALID_PATH) {
return Collections.emptyMap();
}
final Map result = new HashMap<>(URL_INFO_INIT_SIZE);
result.put(HttpConstants.HTTP_URL_SCHEME, protocol);
result.put(HttpConstants.HTTP_URI_SERVICE, tokenizer.nextToken(delim));
result.put(HttpConstants.HTTP_URI_PATH,
formatPath(tokenizer.nextToken(HttpConstants.EMPTY_STR), url.getQuery()));
return result;
}
/**
* 解析url参数信息 http://www.domain.com/serviceName/sayHello?name=1
*
* @param url url地址
* @return url解析后的主机名、路径
*/
public static Map recoverUrl(String url) {
if (StringUtils.isEmpty(url) || !isValidUrl(url)) {
return Collections.emptyMap();
}
String baseSlash = String.valueOf(HttpConstants.HTTP_URL_SINGLE_SLASH);
final StringTokenizer urlTokens = new StringTokenizer(url, baseSlash);
if (urlTokens.countTokens() < MIN_LEN_FOR_VALID_URL) {
return Collections.emptyMap();
}
// http(s):.subString(0, len - 1)
final String rawScheme = urlTokens.nextToken(baseSlash);
String scheme = rawScheme.substring(0, rawScheme.length() - 1);
// domain 域名
Map result = new HashMap<>(URL_INFO_INIT_SIZE);
result.put(HttpConstants.HTTP_URI_HOST, urlTokens.nextToken(baseSlash));
final String serviceName = urlTokens.nextToken(baseSlash);
final String path = urlTokens.nextToken(HttpConstants.EMPTY_STR);
result.put(HttpConstants.HTTP_URI_SERVICE, serviceName);
result.put(HttpConstants.HTTP_URL_SCHEME, scheme);
result.put(HttpConstants.HTTP_URI_PATH, path);
return result;
}
/**
* 针对HttpUrlConnection进行地址重构
*
* @param originUrl 原地址
* @param instance 选择的实例
* @param path 路径
* @return URL
*/
public static Optional rebuildUrlForHttpConnection(URL originUrl, ServiceInstance instance, String path) {
final String protocol = originUrl.getProtocol();
String newUrl = buildNewUrl(protocol, instance.getIp(), instance.getPort(), path);
try {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("[HttpUrlConnection] rebuild url " + newUrl);
}
return Optional.of(new URL(newUrl));
} catch (MalformedURLException e) {
LOGGER.warning("Can not parse to URL for url " + newUrl);
}
return Optional.empty();
}
private static String buildNewUrl(String protocol, String ip, int port, String path) {
return new StringBuilder(protocol)
.append("://")
.append(ip)
.append(":")
.append(port)
.append(path)
.toString();
}
/**
* 打印请求路径
*
* @param hostAndPath 请求路径与服务名
* @param source 请求原, 例如httpclient/http async client
*/
public static void printRequestLog(String source, Map hostAndPath) {
if (!RECORDER.isEnable()) {
return;
}
String path = String.format(Locale.ENGLISH, "/%s%s", hostAndPath.get(HttpConstants.HTTP_URI_SERVICE),
hostAndPath.get(HttpConstants.HTTP_URI_PATH));
LOGGER.log(Level.FINE, String.format(Locale.ENGLISH, "[%s] request [%s] has been intercepted!", source, path));
RECORDER.beforeRequest();
}
/**
* 格式化uri
*
* @param uri 目标uri
* @return URI
*/
public static Optional formatUri(String uri) {
if (!isValidUrl(uri)) {
return Optional.empty();
}
try {
return Optional.of(new URI(uri));
} catch (URISyntaxException e) {
LOGGER.fine(String.format(Locale.ENGLISH, "%s is not valid uri!", uri));
return Optional.empty();
}
}
private static boolean isValidUrl(String url) {
final String lowerCaseUrl = url.toLowerCase(Locale.ROOT);
return lowerCaseUrl.startsWith("http") || lowerCaseUrl.startsWith("https");
}
/**
* 构建invoke回调方法函数
*
* @param context 上下文
* @param invokerContext 调用上下文
* @return 调用器
*/
public static Supplier