公司网络调整后本地与Rancher上的开发/测试容器不能互通,重写替换路径为gateway路径实现联调
/*
* Copyright 2013-2023 the original author or authors.
*
* 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
*
* https://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 org.springframework.cloud.openfeign.loadbalancer;
import feign.Client;
import feign.Request;
import feign.Response;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.*;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest;
import org.springframework.retry.RetryListener;
import org.springframework.retry.backoff.BackOffPolicy;
import org.springframework.retry.backoff.NoBackOffPolicy;
import org.springframework.retry.policy.NeverRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.util.Assert;
import org.springframework.util.StreamUtils;
import java.io.IOException;
import java.net.URI;
import java.util.*;
import static org.springframework.cloud.openfeign.loadbalancer.LoadBalancerUtils.buildRequestData;
/**
* A {@link Client} implementation that provides Spring Retry support for requests
* load-balanced with Spring Cloud LoadBalancer.
*
* @author Olga Maciaszek-Sharma
* @author changjin wei(魏昌进)
* @author Wonsik Cheung
* @author Andriy Pikozh
* @since 2.2.6
*/
@SuppressWarnings({"rawtypes", "unchecked"})
class RetryableFeignBlockingLoadBalancerClient implements Client {
private static final String BASE_URL = "172.16.172.130:23740";
private static final Log LOG = LogFactory.getLog(RetryableFeignBlockingLoadBalancerClient.class);
private final Client delegate;
private final LoadBalancerClient loadBalancerClient;
private final LoadBalancedRetryFactory loadBalancedRetryFactory;
private final LoadBalancerClientFactory loadBalancerClientFactory;
private final List transformers;
/**
* @deprecated in favour of
* {@link RetryableFeignBlockingLoadBalancerClient#RetryableFeignBlockingLoadBalancerClient(Client, LoadBalancerClient, LoadBalancedRetryFactory, LoadBalancerClientFactory, List)}
*/
@Deprecated
public RetryableFeignBlockingLoadBalancerClient(Client delegate, LoadBalancerClient loadBalancerClient,
LoadBalancedRetryFactory loadBalancedRetryFactory,
LoadBalancerProperties properties,
LoadBalancerClientFactory loadBalancerClientFactory) {
this.delegate = delegate;
this.loadBalancerClient = loadBalancerClient;
this.loadBalancedRetryFactory = loadBalancedRetryFactory;
this.loadBalancerClientFactory = loadBalancerClientFactory;
this.transformers = Collections.emptyList();
}
/**
* @deprecated in favour of
* {@link RetryableFeignBlockingLoadBalancerClient#RetryableFeignBlockingLoadBalancerClient(Client, LoadBalancerClient, LoadBalancedRetryFactory, LoadBalancerClientFactory, List)}
*/
@Deprecated
public RetryableFeignBlockingLoadBalancerClient(Client delegate, LoadBalancerClient loadBalancerClient,
LoadBalancedRetryFactory loadBalancedRetryFactory,
LoadBalancerClientFactory loadBalancerClientFactory) {
this.delegate = delegate;
this.loadBalancerClient = loadBalancerClient;
this.loadBalancedRetryFactory = loadBalancedRetryFactory;
this.loadBalancerClientFactory = loadBalancerClientFactory;
this.transformers = Collections.emptyList();
}
public RetryableFeignBlockingLoadBalancerClient(Client delegate, LoadBalancerClient loadBalancerClient,
LoadBalancedRetryFactory loadBalancedRetryFactory,
LoadBalancerClientFactory loadBalancerClientFactory,
List transformers) {
this.delegate = delegate;
this.loadBalancerClient = loadBalancerClient;
this.loadBalancedRetryFactory = loadBalancedRetryFactory;
this.loadBalancerClientFactory = loadBalancerClientFactory;
this.transformers = transformers;
}
@Override
public Response execute(Request request, Request.Options options) throws IOException {
final URI originalUri = URI.create(request.url());
String serviceId = originalUri.getHost();
Assert.state(serviceId != null, "Request URI does not contain a valid hostname: " + originalUri);
final LoadBalancedRetryPolicy retryPolicy = loadBalancedRetryFactory.createRetryPolicy(serviceId,
loadBalancerClient);
RetryTemplate retryTemplate = buildRetryTemplate(serviceId, request, retryPolicy);
return retryTemplate.execute(context -> {
Request feignRequest = null;
ServiceInstance retrievedServiceInstance = null;
Set supportedLifecycleProcessors = LoadBalancerLifecycleValidator
.getSupportedLifecycleProcessors(
loadBalancerClientFactory.getInstances(serviceId, LoadBalancerLifecycle.class),
RetryableRequestContext.class, ResponseData.class, ServiceInstance.class);
String hint = getHint(serviceId);
DefaultRequest lbRequest = new DefaultRequest<>(
new RetryableRequestContext(null, buildRequestData(request), hint));
// On retries the policy will choose the server and set it in the context
// and extract the server and update the request being made
if (context instanceof LoadBalancedRetryContext lbContext) {
retrievedServiceInstance = lbContext.getServiceInstance();
if (retrievedServiceInstance == null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Service instance retrieved from LoadBalancedRetryContext: was null. "
+ "Reattempting service instance selection");
}
ServiceInstance previousServiceInstance = lbContext.getPreviousServiceInstance();
lbRequest.getContext().setPreviousServiceInstance(previousServiceInstance);
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStart(lbRequest));
retrievedServiceInstance = loadBalancerClient.choose(serviceId, lbRequest);
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("Selected service instance: %s", retrievedServiceInstance));
}
lbContext.setServiceInstance(retrievedServiceInstance);
}
if (retrievedServiceInstance == null) {
if (LOG.isWarnEnabled()) {
LOG.warn("Service instance was not resolved, executing the original request");
}
org.springframework.cloud.client.loadbalancer.Response lbResponse =
new DefaultResponse(
retrievedServiceInstance);
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
.onComplete(new CompletionContext(
CompletionContext.Status.DISCARD, lbRequest, lbResponse)));
feignRequest = request;
} else {
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("Using service instance from LoadBalancedRetryContext: %s",
retrievedServiceInstance));
}
String reconstructedUrl = originalUri.toString().replaceFirst(serviceId, BASE_URL + "/" + serviceId);
LOG.info("替换url为:" + reconstructedUrl);
feignRequest = buildRequest(request, reconstructedUrl, retrievedServiceInstance);
//String reconstructedUrl = this.loadBalancerClient.reconstructURI(retrievedServiceInstance, originalUri).toString();
//feignRequest = this.buildRequest(request, reconstructedUrl, retrievedServiceInstance);
}
}
org.springframework.cloud.client.loadbalancer.Response lbResponse = new DefaultResponse(
retrievedServiceInstance);
LoadBalancerProperties loadBalancerProperties = loadBalancerClientFactory.getProperties(serviceId);
Response response = LoadBalancerUtils.executeWithLoadBalancerLifecycleProcessing(delegate, options,
feignRequest, lbRequest, lbResponse, supportedLifecycleProcessors,
retrievedServiceInstance != null);
int responseStatus = response.status();
if (retryPolicy != null && retryPolicy.retryableStatusCode(responseStatus)) {
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("Retrying on status code: %d", responseStatus));
}
byte[] byteArray = response.body() == null ? new byte[]{}
: StreamUtils.copyToByteArray(response.body().asInputStream());
response.close();
throw new LoadBalancerResponseStatusCodeException(serviceId, response, byteArray,
URI.create(request.url()));
}
return response;
}, new LoadBalancedRecoveryCallback() {
@Override
protected Response createResponse(Response response, URI uri) {
return response;
}
});
}
protected Request buildRequest(Request request, String reconstructedUrl) {
return Request.create(request.httpMethod(), reconstructedUrl, request.headers(), request.body(),
request.charset(), request.requestTemplate());
}
protected Request buildRequest(Request request, String reconstructedUrl, ServiceInstance instance) {
Request newRequest = buildRequest(request, reconstructedUrl);
if (transformers != null) {
for (LoadBalancerFeignRequestTransformer transformer : transformers) {
newRequest = transformer.transformRequest(newRequest, instance);
}
}
return newRequest;
}
private RetryTemplate buildRetryTemplate(String serviceId, Request request, LoadBalancedRetryPolicy retryPolicy) {
RetryTemplate retryTemplate = new RetryTemplate();
BackOffPolicy backOffPolicy = this.loadBalancedRetryFactory.createBackOffPolicy(serviceId);
retryTemplate.setBackOffPolicy(backOffPolicy == null ? new NoBackOffPolicy() : backOffPolicy);
RetryListener[] retryListeners = this.loadBalancedRetryFactory.createRetryListeners(serviceId);
if (retryListeners != null && retryListeners.length != 0) {
retryTemplate.setListeners(retryListeners);
}
retryTemplate.setRetryPolicy(
!loadBalancerClientFactory.getProperties(serviceId).getRetry().isEnabled() || retryPolicy == null
? new NeverRetryPolicy() : new InterceptorRetryPolicy(toHttpRequest(request), retryPolicy,
loadBalancerClient, serviceId));
return retryTemplate;
}
// Visible for Sleuth instrumentation
public Client getDelegate() {
return delegate;
}
private HttpRequest toHttpRequest(Request request) {
return new HttpRequest() {
@Override
public HttpMethod getMethod() {
return HttpMethod.valueOf(request.httpMethod().name());
}
@Override
public URI getURI() {
return URI.create(request.url());
}
@Override
public HttpHeaders getHeaders() {
Map> headers = new HashMap<>();
Map> feignHeaders = request.headers();
for (String key : feignHeaders.keySet()) {
headers.put(key, new ArrayList<>(feignHeaders.get(key)));
}
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.putAll(headers);
return httpHeaders;
}
};
}
private String getHint(String serviceId) {
LoadBalancerProperties properties = loadBalancerClientFactory.getProperties(serviceId);
String defaultHint = properties.getHint().getOrDefault("default", "default");
String hintPropertyValue = properties.getHint().get(serviceId);
return hintPropertyValue != null ? hintPropertyValue : defaultHint;
}
}