一次基于Http协议的远程过程调用的实现

远程过程调用是什么呢?通俗来说就是程序员在访问远程资源的时候,就跟在本地访问一样。实现远程过程调用远没有想象那么复杂,简单来说就是将放在业务里面的调用外部系统逻辑的代码独立开来,调用者不需要考虑远程调用的实现细节,与在本地调用一个服务层一样。很多厂家的sdk也都是这样的方式,就拿腾讯云的短信为例,看似只需要填写短信的相关配置,然后调用其给定的方法就行了,其实还内含了例如网络传输,序列化与反序列化的东西,把这些问题给屏蔽掉了。

当然,简单的对http接口调用进行封装,算不上是真正的远程过程调用,只是借用RPC的概念,通过对调用接口的封装,屏蔽掉不同接口调用者网络实现和序列化与反序列化的实现差异。减少不必要的调试。

我现在是按照下面的方式实现的。首先定义一个通用的网络请求方法,这是一个简单的工具类

public class NetWorkUtil{

    public static final int HTTP_METHOD_GET = 1;
    public static final int HTTP_METHOD_HEAD = 2;
    public static final int HTTP_METHOD_POST = 3;
    public static final int HTTP_METHOD_PATCH = 4;
    public static final int HTTP_METHOD_PUT = 5;

    public static final List<String[]> reqHeaderList = Arrays.asList(new String[][]{
            {"Accept-Encoding", "gzip, deflate, sdch"},
            {"Accept-Language", "zh-CN,zh;q=0.8"},
            {"Connection", "keep-alive"},
            {"User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.130 Safari/537.36"}
    });

    /**
     * 获取 http 请求头
     *
     * @param xAuth acunetix key
     * @return http 请求头
     */
    public static Map<String, String> getReqHeaders(String xAuth) {
        Map<String, String> reqHeaders = new HashMap<>();
        reqHeaderList.forEach(header -> {
            reqHeaders.put(header[0], header[1]);
        });
        reqHeaders.put("X-Auth", xAuth);
        return reqHeaders;
    }

    /**
     * http 应答
     */
    public static class HttpResponse {
        public CloseableHttpResponse response;
        public String body;
    }

    /**
     * 获取应答
     *
     * @param httpClient  http 客户端
     * @param method      请求方法
     * @param httpRequest http 请求
     * @return http 响应
     */
    public static HttpResponse getResponse(CloseableHttpClient httpClient, int method, HttpRequestBase httpRequest) {
        CloseableHttpResponse httpResponse = null;
        String body = null;
        try {
            httpResponse = httpClient.execute(httpRequest);
            if (method != HTTP_METHOD_HEAD) {
                HttpEntity httpEntity = httpResponse.getEntity();
                if (Objects.nonNull(httpEntity)) {
                    BufferedReader reader = new BufferedReader(new InputStreamReader(httpEntity.getContent(), "utf-8"));
                    String str = null;
                    StringBuffer stringBuffer = new StringBuffer();
                    while (Objects.nonNull(str = reader.readLine())) {
                        if (StringUtils.isBlank(str)) {
                            continue;
                        }
                        stringBuffer.append(str);
                    }
                    body = stringBuffer.toString();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            httpResponse = null;
        } finally {
            try {
                httpResponse.close();
            } catch (Exception ex) {
                httpResponse = null;
            }
            try {
                httpClient.close();
            } catch (Exception ex) {
                httpResponse = null;
            }
        }
        if (Objects.isNull(httpResponse)) {
            return null;
        }
        HttpResponse response = new HttpResponse();
        response.response = httpResponse;
        response.body = body;
        return response;
    }

    /**
     * 获取 Http 请求对象
     *
     * @param url     要访问的 url
     * @param method  访问的方式
     * @param headers 请求头
     * @param body    请求内容
     * @return http 请求对象
     */
    public static HttpRequestBase newHttpRequest(String url, int method, Map<String, String> headers, Object body) {
        HttpRequestBase httpRequest = null;
        switch (method) {
            case HTTP_METHOD_GET:
                httpRequest = new HttpGet(url);
                break;
            case HTTP_METHOD_HEAD:
                httpRequest = new HttpHead(url);
                break;
            case HTTP_METHOD_POST:
                httpRequest = new HttpPost(url);
                break;
            case HTTP_METHOD_PATCH:
                httpRequest = new HttpPatch(url);
                break;
            case HTTP_METHOD_PUT:
                httpRequest = new HttpPut(url);
                break;
            default:
                return null;
        }
        if (httpRequest instanceof HttpPost || httpRequest instanceof HttpPatch || httpRequest instanceof HttpPut) {
            try {
                if (body instanceof String) {
                    ((HttpEntityEnclosingRequest) httpRequest).setEntity(new StringEntity((String) body, ContentType.APPLICATION_JSON));
                } else if (body instanceof Map) {
                    List<NameValuePair> nameValuePairs = new ArrayList<>();
                    ((Map<String, String>) body).forEach((key, value) -> {
                        nameValuePairs.add(new BasicNameValuePair(key, value));
                    });
                    if (httpRequest instanceof HttpPost) {
                        ((HttpPost) httpRequest).setEntity(new UrlEncodedFormEntity(nameValuePairs));
                    } else if (httpRequest instanceof HttpPut) {
                        ((HttpPut) httpRequest).setEntity(new UrlEncodedFormEntity(nameValuePairs));
                    } else if (httpRequest instanceof HttpPatch) {
                        ((HttpPatch) httpRequest).setEntity(new UrlEncodedFormEntity(nameValuePairs));
                    } else {
                        throw new RuntimeException("不支持的 httpRequest: "+httpRequest.getMethod());
                    }
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                return null;
            }
        }
        httpRequest.setConfig(RequestConfig.custom().setConnectTimeout(5000).setSocketTimeout(5000).build());
        final HttpRequestBase httpRequestBase = httpRequest;
        if (Objects.nonNull(headers)) {
            headers.forEach((key, value) -> httpRequestBase.addHeader(key, value));
        }
        return httpRequest;
    }

    /**
     * 创建一个允许访问自签名站点的 http 客户端
     *
     * @return 一个允许访问自签名站点的 http 客户端
     */
    public static CloseableHttpClient createAcceptSelfSignedCertificateClient() {
        try {
            // use the TrustSelfSignedStrategy to allow Self Signed Certificates
            SSLContext sslContext = SSLContextBuilder
                    .create()
                    .loadTrustMaterial(new TrustSelfSignedStrategy())
                    .build();

            // we can optionally disable hostname verification.
            // if you don't want to further weaken the security, you don't have to include this.
            HostnameVerifier allowAllHosts = new NoopHostnameVerifier();

            // create an SSL Socket Factory to use the SSLContext with the trust self signed certificate strategy
            // and allow all hosts verifier.
            SSLConnectionSocketFactory connectionFactory = new SSLConnectionSocketFactory(sslContext, allowAllHosts);

            // finally create the HttpClient using HttpClient factory methods and assign the ssl socket factory
            return HttpClients
                    .custom()
                    .setSSLSocketFactory(connectionFactory)
                    .build();
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }



    public static HttpResponse getResponseWithLine(CloseableHttpClient httpClient, int method, HttpRequestBase httpRequest) {
        CloseableHttpResponse httpResponse = null;
        String body = null;
        try {
            httpResponse = httpClient.execute(httpRequest);
            if (method != HTTP_METHOD_HEAD) {
                HttpEntity httpEntity = httpResponse.getEntity();
                if (Objects.nonNull(httpEntity)) {
                    BufferedReader reader = new BufferedReader(new InputStreamReader(httpEntity.getContent(), "utf-8"));
                    String str = null;
                    StringBuffer stringBuffer = new StringBuffer();
                    while (Objects.nonNull(str = reader.readLine())) {
                        if (StringUtils.isBlank(str)) {
                            continue;
                        }
                        str = str + "\r\n";
                        stringBuffer.append(str);
                    }
                    body = stringBuffer.toString();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            httpResponse = null;
        } finally {
            try {
                httpResponse.close();
            } catch (Exception ex) {
                httpResponse = null;
            }
            try {
                httpClient.close();
            } catch (Exception ex) {
                httpResponse = null;
            }
        }
        if (Objects.isNull(httpResponse)) {
            return null;
        }
        HttpResponse response = new HttpResponse();
        response.response = httpResponse;
        response.body = body;
        return response;
    }
}

java工具类在使用的时候尽量不要使用静态引入 + 星号的方法,一旦用多了,可能就不知道某个属性、常量或者变量方法究竟是哪个工具类里面的了。

然后利用此网络工具类构建出网络请求就好了,具体的方案有很多。最后我给大家看看效果。

我们在封装的时候,将整个(也可分开,看架构)包装模块定义到一个服务中,在需要使用的地方直接注入该服务就行了
下面的代码中的业务模块是注册逻辑的一部分,用到了两个服务。
在这里插入图片描述
你能看出那个服务是远程服务吗?看不出来?远程过程调用达到的就是这么个效果,减少调用代码对业务代码的侵入性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海燕技术栈

你的鼓励我的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值