AWS外站代理解决方案

1.现状介绍

jenkins构建项目部署在长乐环境,由于长乐环境与AWS、AWS-CALIFORNIA环境网络很不稳定,导致经常请求AWS、AWS-CALIFORNIA环境服务时报超时错误,很是影响项目打包构建。

来看下,各环境网络互通情况:

113706_V55s_2470917.png

可以看到,目前只有无锡环境与AWS、AWS-CALIFORNIA环境网络稳定。所以,我们可以通过访问无锡环境去做AWS代理转发,从而实现访问AWS、AWS-CALIFORNIA环境服务正常。

2.解决方案

在无锡环境部署一套代理服务,用于专门代理转发AWS外站。这样,长乐环境的项目要访问AWS外站服务,就可以通过访问无锡环境的代理服务,从而实现访问AWS外站。

我们再来看下,现在各环境网络互通情况:

114337_JWMw_2470917.png

3.代理模式

  • 代理服务

request:

GET|POST|PUT https://xxx/proxy

headers:

APF-HEADER-ACTUAL-URL : 实际访问的地址

  • 客户端

部署在长乐环境的jenkins项目,在构建的时候,不仅会访问无锡环境的服务,而且会访问AWS、AWS-CALIFORNIA环境服务。在做客户端统一调用的时候,考虑到访问AWS、AWS-CALIFORNIA环境服务需要访问无锡环境的代理服务,为了不破坏原来访问无锡环境服务的方式,只需要判断所请求的服务是否为AWS、AWS-CALIFORNIA环境服务,然后通过代理服务做跳转即可。所以我们想到了代理模式,即CGLIB动态代理。

CGLIB动态代理类:

import hudson.EnvVars;

import java.lang.reflect.Method;

import net.sf.json.JSONArray;

import org.apache.commons.lang3.StringUtils;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import com.alibaba.fastjson.JSONObject;


public class HttpClientProxy implements MethodInterceptor {
    
    private EnvVars envVars;
    
    /**
     * @param envVars
     */
    public HttpClientProxy(EnvVars envVars) {
        super();
        this.envVars = envVars;
    }

    private Enhancer enhancer = new Enhancer();
    
    public Object getProxy(Class<?> clazz){  
        enhancer.setSuperclass(clazz);  
        enhancer.setCallback(this);  
        return enhancer.create();  
    } 

    /**
     * <p>Description: 拦截所有目标类方法的调用</p>
     * @param obj 目标实例对象
     * @param method 目标方法的反射对象
     * @param args 方法的参数
     * @param proxy 代理类的实例 
     * @return
     */
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        String url = (String) args[0];
        args[0] = this.checkUrl(url);// 重新包装URL
        
        //代理类调用父类的方法
        return proxy.invokeSuper(obj, args);  
    }
    
    /**
     * <p>Description: 判断当前请求的URL是否在需要代理跳转的URL里面</p>
     * @param url 当前请求的URL
     * @return
     */
    private String checkUrl(String url) {
        JSONObject urlJSONObject = null;
        
        String proxyUrlArr = envVars.get("proxy_url");// 需要代理跳转的URL
        
        if(StringUtils.isNotBlank(proxyUrlArr)) {
            JSONArray proxyUrlJSONArray = JSONArray.fromObject(proxyUrlArr);
            
            if(null != proxyUrlJSONArray) {
                for (Object object : proxyUrlJSONArray.toArray()) {
                    String proxyUrl = (String) object;
                    
                    // 如果当前请求的URL在需要代理跳转的URL里面,且代理URL不为空时,则使用代理URL
                    if(url.startsWith(proxyUrl)) {
                        String proxyServerHost = envVars.get("proxy_server_host");
                        
                        if(StringUtils.isNotBlank(proxyServerHost)) {
                            urlJSONObject = new JSONObject();
                            urlJSONObject.put("url", url);
                            urlJSONObject.put("proxy_url", proxyServerHost);
                        }
                        
                        break;
                    }
                }
            }
        }
        
        if(null != urlJSONObject) {
            return urlJSONObject.toJSONString();
        }
        
        return url;
    }
    
}

 请求类:

import java.io.PrintStream;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;

import com.alibaba.fastjson.JSONObject;
import com.nd.sdp.portal.jenkins.factory.util.HttpsUtil;

public class HttpClientImpl {

    /**
     * <p>Description:  发送post请求 </p>
     * @param url 请求URL
     * @param requestBody 请求body
     * @param isPrint 是否打印响应body
     * @param printStream
     */
    public String postForObject(String url, String requestBody, boolean isPrint, PrintStream printStream) {
        boolean isProxy = false;// 是否需要代理
        String proxyUrl = "";
        String actualUrl = "";
        
        try {
            JSONObject urlJSONObject = (JSONObject) JSONObject.parse(url);
            actualUrl = urlJSONObject.getString("url");// 真实URL
            proxyUrl = urlJSONObject.getString("proxy_url");// 代理URL
            
            isProxy = true;
        } catch (Exception e) {
            proxyUrl = url;
            isProxy = false;
        }
        
        PostMethod postMethod = new PostMethod(proxyUrl);
        printStream.println("[INFO] URL(POST):" + proxyUrl + " body:" + requestBody);
        
        if(isProxy) {
            postMethod.setRequestHeader("APF-HEADER-ACTUAL-URL", actualUrl);// 使用代理时,需要Header头上加参数
            printStream.println("[INFO] setRequestHeader :" + actualUrl);
        }
        
        String responseBodyStr = "";
        boolean flag = false;
        
        //重试三次
        for (int i = 0; i < 3; i++) {
            if(flag){
                break;
            }
            
            try {
                postMethod.setRequestEntity(new StringRequestEntity(requestBody, "application/json", "utf-8"));
                postMethod.addRequestHeader(new Header("Content-Type", "application/json;charset=utf-8"));

                HttpClient client = new HttpClient();
                client.getHttpConnectionManager().getParams().setSoTimeout(120 * 1000);
                client.getHttpConnectionManager().getParams().setConnectionTimeout(60000);
                int status = client.executeMethod(postMethod);

                String prefix = status == 200 ? "[INFO] 发布成功" : "【ERROR】  发布失败";
                printStream.println(prefix + " statusCode:" + status);
                
                String response = postMethod.getResponseBodyAsString();
                if(isPrint) {
                    printStream.println(prefix + " response body:" + response);
                }
                
                if (status!=200) {
                    throw new Exception("status " + status);
                }
                
                responseBodyStr = response;
                
                flag = true;
                
            } catch (Exception e) {
                if(i==2){
                    String msg = "【ERROR】 发布失败: " + e.getMessage() + ",第" + i + "次调用";
                    printStream.println(msg);
                    
                    throw new RuntimeException(e);
                } else {
                    String msg = "发布失败: " + e.getMessage() + ",第" + i + "次调用";
                    printStream.println(msg);
                }
            } finally {
                postMethod.releaseConnection();
            }
            
        }
        
        return responseBodyStr;
    }
    
    /**
     * <p>Description:  发送put请求 </p>
     * @param url 请求URL
     * @param requestBody 请求body
     * @param isPrint 是否打印响应body
     * @param printStream
     */
    public String putForObject(String url, String requestBody, boolean isPrint, PrintStream printStream) {
        boolean isProxy = false;// 是否需要代理
        String proxyUrl = "";
        String actualUrl = "";
        
        try {
            JSONObject urlJSONObject = (JSONObject) JSONObject.parse(url);
            actualUrl = urlJSONObject.getString("url");// 真实URL
            proxyUrl = urlJSONObject.getString("proxy_url");// 代理URL
            
            isProxy = true;
        } catch (Exception e) {
            proxyUrl = url;
            isProxy = false;
        }
        
        PutMethod putMethod = new PutMethod(proxyUrl);
        printStream.println("[INFO] URL(PUT):" + proxyUrl + " body:" + requestBody);
        
        if(isProxy) {
            putMethod.setRequestHeader("APF-HEADER-ACTUAL-URL", actualUrl);// 使用代理时,需要Header头上加参数
            printStream.println("[INFO] setRequestHeader :" + actualUrl);
        }
        
        String responseBodyStr = "";
        boolean flag = false;
        
        //重试三次
        for (int i = 0; i < 3; i++) {
            if(flag){
                break;
            }
            
            try {
                putMethod.setRequestEntity(new StringRequestEntity(requestBody, "application/json", "utf-8"));
                putMethod.addRequestHeader(new Header("Content-Type", "application/json;charset=utf-8"));

                HttpClient client = new HttpClient();
                client.getHttpConnectionManager().getParams().setSoTimeout(120 * 1000);
                client.getHttpConnectionManager().getParams().setConnectionTimeout(60000);
                int status = client.executeMethod(putMethod);

                String prefix = status == 200 ? "[INFO] 发布成功" : "【ERROR】  发布失败";
                printStream.println(prefix + " statusCode:" + status);
                
                String response = putMethod.getResponseBodyAsString();
                if(isPrint) {
                    printStream.println(prefix + " response body:" + response);
                }
                
                if (status!=200) {
                    throw new Exception("status " + status);
                }
                
                responseBodyStr = response;
                
                flag = true;
                
            } catch (Exception e) {
                if(i==2){
                    String msg = "【ERROR】 发布失败: " + e.getMessage() + ",第" + i + "次调用";
                    printStream.println(msg);
                    
                    throw new RuntimeException(e);
                } else {
                    String msg = "发布失败: " + e.getMessage() + ",第" + i + "次调用";
                    printStream.println(msg);
                }
            } finally {
                putMethod.releaseConnection();
            }
            
        }
        
        return responseBodyStr;
    }
    
    /**
     * <p>Description: 发送get请求</p>
     * @param url 请求URL
     * @param printStream
     * @return
     */
    public String getForObject(String url, PrintStream printStream) {
        boolean isProxy = false;// 是否需要代理
        String proxyUrl = "";
        String actualUrl = "";
        
        try {
            JSONObject urlJSONObject = (JSONObject) JSONObject.parse(url);
            actualUrl = urlJSONObject.getString("url");// 真实URL
            proxyUrl = urlJSONObject.getString("proxy_url");// 代理URL
            
            isProxy = true;
        } catch (Exception e) {
            proxyUrl = url;
            isProxy = false;
        }
        
        GetMethod getMethod = new GetMethod(proxyUrl);
        printStream.println("[INFO] URL(GET): " + proxyUrl);
        
        if(isProxy) {
            getMethod.setRequestHeader("APF-HEADER-ACTUAL-URL", actualUrl);// 使用代理时,需要Header头上加参数
            printStream.println("[INFO] setRequestHeader :" + actualUrl);
        } else {
            if(proxyUrl.startsWith("https://")) {// 无视Https证书是否正确
                return HttpsUtil.getMethod(proxyUrl);
            }
        }
        
        String responseBodyStr = "";

        boolean flag = false;
        //重试三次
        for (int i = 0; i < 3; i++) {
            if(flag){
                break;
            }
            
            try {
                HttpClient client = new HttpClient();
                client.getHttpConnectionManager().getParams().setSoTimeout(120 * 1000);
                client.getHttpConnectionManager().getParams().setConnectionTimeout(60000);
                
                int status = client.executeMethod(getMethod);

                String prefix = status == 200 ? "[INFO] 获取成功" : "【ERROR】  获取失败";
                printStream.println(prefix + " statusCode:" + status);
                if (status!=200) {
                    throw new Exception("status " + status);  
                }
                
                byte[] responseBody = getMethod.getResponseBody();
                responseBodyStr = new String(responseBody, "utf-8");
                
                flag = true;
                
            } catch (Exception e) {
                if(i==2){
                    String msg = "【ERROR】获取失败: " + e.getMessage() + ",第" + i + "次调用";
                    printStream.println(msg);
                    
                    throw new RuntimeException(e);
                } else {
                    String msg = "获取失败: " + e.getMessage() + ",第" + i + "次调用";
                    printStream.println(msg);
                }
            } finally {
                getMethod.releaseConnection();
            }
            
        }
        
        return responseBodyStr;
    }
    
}

客户端调用方式:

HttpClientProxy proxy = new HttpClientProxy(envs); 
HttpClientImpl httpClient = (HttpClientImpl) proxy.getProxy(HttpClientImpl.class);

// GET
String url = "";
String responeBody = httpClient.getForObject(url, listener.getLogger());

// POST
httpClient.postForObject(url, obj.toJSONString(), false, listener.getLogger());

URL配置信息:

{
    "proxy_server_host":"https://xxx/proxy", // 代理服务URL
	"proxy_url":[// 需要被代理的AWS外站地址
		"https://xxx.aws.com/",
		"https://xxx.awsca.com/"
	]
}

 

转载于:https://my.oschina.net/lienson/blog/1506479

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值