当传入流量使用 Load Balancer URL 时,如何捕获用于满足请求的服务器?
How to capture the server used to fulfill a request when incoming traffic is using Load Balancer URL?
我有一个 Spring Boot Java REST 应用程序,其中有许多 API 暴露给我们的客户和 UI。我的任务是实现一个事务日志框架,该框架将捕获传入的事务以及我们发送的响应。
我使用 Spring AOP 和 Around inspect 进行这项工作,目前我正在利用 HttpServletRequest 和 HttpServletResponse 对象来获取我需要的大量数据。
在我的本地系统中,我在捕获所使用的服务器时没有任何问题,因为我直接连接到我的系统。然而,一旦我部署了我的代码,我就看到负载均衡器 URL 被捕获而不是实际的服务器名称。
我还使用 Eureka 按名称发现 API,因为它只是 HAProxy 上的一个应用程序 运行。
想象一下这个流程:
/*
UI -> https://my-lb-url/service-sidecar/createUser
HAProxy directs traffic to -> my-lb-url/service-sidecar/ to one of below:
my-server-1:12345
my-server-2:12345
my-server-3:12345
Goal : http://my-server-1:1235/createUser
Actual: https://my-lb-url/createUser
这是我用来获取传入的代码 URL。
String url = httpRequest.getRequestURL().toString();
if(httpRequest.getQueryString() != null){
transaction.setApi(url + "?" + httpRequest.getQueryString());
} else {
transaction.setApi(url);
}
注:
我对 HAProxy/Eurkea/etc 不太熟悉。正如我所愿。如果上述内容似乎不对或不对,那么我深表歉意。我们的系统管理员配置了这些并将开发人员拒之门外。
更新
这是我用来构造请求的新代码 URL,但我仍然看到相同的输出。
// Utility Class
public static String constructRequestURL(HttpServletRequest httpRequest) {
StringBuilder url = new StringBuilder(httpRequest.getScheme());
url.append("://").append(httpRequest.getServerName());
int port = httpRequest.getServerPort();
if(port != 80 && port != 443) {
url.append(":").append(port);
}
url.append(httpRequest.getContextPath()).append(httpRequest.getServletPath());
if(httpRequest.getPathInfo() != null) {
url.append(httpRequest.getPathInfo());
}
if(httpRequest.getQueryString() != null) {
url.append("?").append(httpRequest.getQueryString());
}
return url.toString();
}
// Service Class
transaction.setApi(CommonUtil.constructRequestURL(httpRequest));
我找到了解决此问题的方法,但这不是最干净的方法,如果可能的话,我很乐意采纳其他建议。
- 我正在自动连接 application.yml 的端口号。
- 我在托管应用程序的 Linux 服务器上 运行 "hostname" 命令以确定满足请求的服务器。
现在存储在事务日志中的 URL 是准确的。
--
@Autowired
private int serverPort;
/*
* ...
*/
private String constructRequestURL(HttpServletRequest httpRequest) {
StringBuilder url = new StringBuilder(httpRequest.getScheme())
.append("://").append(findHostnameFromServer()).append(":").append(serverPort)
.append(httpRequest.getContextPath()).append(httpRequest.getServletPath());
if(httpRequest.getPathInfo() != null) {
url.append(httpRequest.getPathInfo());
}
if(httpRequest.getQueryString() != null) {
url.append("?").append(httpRequest.getQueryString());
}
return url.toString();
}
private String findHostnameFromServer(){
String hostname = null;
LOGGER.info("Attempting to Find Hostname from Server...");
try {
Process process = Runtime.getRuntime().exec(new String[]{"hostname"});
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
hostname = reader.readLine();
}
} catch (IOException e) {
LOGGER.error(CommonUtil.ERROR, e);
}
LOGGER.info("Found Hostname: {}", hostname);
return hostname;
}
我有一个 Spring Boot Java REST 应用程序,其中有许多 API 暴露给我们的客户和 UI。我的任务是实现一个事务日志框架,该框架将捕获传入的事务以及我们发送的响应。
我使用 Spring AOP 和 Around inspect 进行这项工作,目前我正在利用 HttpServletRequest 和 HttpServletResponse 对象来获取我需要的大量数据。
在我的本地系统中,我在捕获所使用的服务器时没有任何问题,因为我直接连接到我的系统。然而,一旦我部署了我的代码,我就看到负载均衡器 URL 被捕获而不是实际的服务器名称。
我还使用 Eureka 按名称发现 API,因为它只是 HAProxy 上的一个应用程序 运行。
想象一下这个流程:
/*
UI -> https://my-lb-url/service-sidecar/createUser
HAProxy directs traffic to -> my-lb-url/service-sidecar/ to one of below:
my-server-1:12345
my-server-2:12345
my-server-3:12345
Goal : http://my-server-1:1235/createUser
Actual: https://my-lb-url/createUser
这是我用来获取传入的代码 URL。
String url = httpRequest.getRequestURL().toString();
if(httpRequest.getQueryString() != null){
transaction.setApi(url + "?" + httpRequest.getQueryString());
} else {
transaction.setApi(url);
}
注:
我对 HAProxy/Eurkea/etc 不太熟悉。正如我所愿。如果上述内容似乎不对或不对,那么我深表歉意。我们的系统管理员配置了这些并将开发人员拒之门外。
更新
这是我用来构造请求的新代码 URL,但我仍然看到相同的输出。
// Utility Class
public static String constructRequestURL(HttpServletRequest httpRequest) {
StringBuilder url = new StringBuilder(httpRequest.getScheme());
url.append("://").append(httpRequest.getServerName());
int port = httpRequest.getServerPort();
if(port != 80 && port != 443) {
url.append(":").append(port);
}
url.append(httpRequest.getContextPath()).append(httpRequest.getServletPath());
if(httpRequest.getPathInfo() != null) {
url.append(httpRequest.getPathInfo());
}
if(httpRequest.getQueryString() != null) {
url.append("?").append(httpRequest.getQueryString());
}
return url.toString();
}
// Service Class
transaction.setApi(CommonUtil.constructRequestURL(httpRequest));
我找到了解决此问题的方法,但这不是最干净的方法,如果可能的话,我很乐意采纳其他建议。
- 我正在自动连接 application.yml 的端口号。
- 我在托管应用程序的 Linux 服务器上 运行 "hostname" 命令以确定满足请求的服务器。
现在存储在事务日志中的 URL 是准确的。
--
@Autowired
private int serverPort;
/*
* ...
*/
private String constructRequestURL(HttpServletRequest httpRequest) {
StringBuilder url = new StringBuilder(httpRequest.getScheme())
.append("://").append(findHostnameFromServer()).append(":").append(serverPort)
.append(httpRequest.getContextPath()).append(httpRequest.getServletPath());
if(httpRequest.getPathInfo() != null) {
url.append(httpRequest.getPathInfo());
}
if(httpRequest.getQueryString() != null) {
url.append("?").append(httpRequest.getQueryString());
}
return url.toString();
}
private String findHostnameFromServer(){
String hostname = null;
LOGGER.info("Attempting to Find Hostname from Server...");
try {
Process process = Runtime.getRuntime().exec(new String[]{"hostname"});
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
hostname = reader.readLine();
}
} catch (IOException e) {
LOGGER.error(CommonUtil.ERROR, e);
}
LOGGER.info("Found Hostname: {}", hostname);
return hostname;
}