美文网首页
基础的HTTPClient搭建注意事项(中)

基础的HTTPClient搭建注意事项(中)

作者: 佛系男子 | 来源:发表于2018-01-13 00:29 被阅读0次

    项目结构更新:

    结构图V1.1

    修改了replaceBodyParamsreplaceParams,更加直观

    新加了asserExpected函数作为判断断言类似的,接口测试不只要测成功的例子,也要测失败的例子。当初真的是想当然了,这个函数我遇到了些麻烦,会在文章结尾说明下。


    首先,放上该项目所用到的包依赖,以免用错包就尴尬了

    package com.mhc.wey.core.httpInterface;

    import com.alibaba.fastjson.JSON;

    import com.alibaba.fastjson.JSONObject;

    import com.mhc.wey.dal.model.HttpInterfaceCaseDO;

    import com.subaru.common.entity.BizResult;

    import jdk.nashorn.internal.runtime.regexp.joni.exception.ValueException;

    import lombok.extern.slf4j.Slf4j;

    import org.apache.commons.lang3.StringUtils;

    import org.apache.http.*;

    import org.apache.http.client.HttpRequestRetryHandler;

    import org.apache.http.client.config.RequestConfig;

    import org.apache.http.client.entity.UrlEncodedFormEntity;

    import org.apache.http.client.methods.CloseableHttpResponse;

    import org.apache.http.client.methods.HttpGet;

    import org.apache.http.client.methods.HttpPost;

    import org.apache.http.client.protocol.HttpClientContext;

    import org.apache.http.conn.ConnectTimeoutException;

    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;

    import org.apache.http.conn.ssl.X509HostnameVerifier;

    import org.apache.http.cookie.Cookie;

    import org.apache.http.entity.StringEntity;

    import org.apache.http.impl.client.CloseableHttpClient;

    import org.apache.http.impl.client.HttpClients;

    import org.apache.http.impl.client.LaxRedirectStrategy;

    import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;

    import org.apache.http.message.BasicHeader;

    import org.apache.http.message.BasicNameValuePair;

    import org.apache.http.protocol.HttpContext;

    import org.apache.http.ssl.SSLContextBuilder;

    import org.apache.http.ssl.TrustStrategy;

    import org.apache.http.util.EntityUtils;

    import org.springframework.context.annotation.Lazy;

    import org.springframework.stereotype.Service;

    import javax.net.ssl.*;

    import java.io.IOException;

    import java.io.InterruptedIOException;

    import java.net.UnknownHostException;

    import java.security.GeneralSecurityException;

    import java.security.cert.CertificateException;

    import java.security.cert.X509Certificate;

    import java.util.*;

    用到的装饰器:

    @Service

    @Slf4j

    @Lazy

    上面用到了两个我司自定义的包,已经标注出来了

    com.mhc.wey.dal.model.HttpInterfaceCaseDO为接口测试用例数据(数据库导入)

    com.subaru.common.entity.BizResult为消息返回的对象


    execute代码如下

    BizResult bizResult =null;

    //执行请求

    BizResult executeHttpRequestResult = executeEncapsulation(httpInterfaceCaseDO);

    if (! executeHttpRequestResult.isSuccess()) {

    return executeHttpRequestResult;

    }

    CloseableHttpResponse response = (CloseableHttpResponse) executeHttpRequestResult.getData();

    log.info("开始解析Response");

    //解析response

    try {

    if (assertExpected(response, httpInterfaceCaseDO)) {

    setReplaceMap(httpInterfaceCaseDO.getResponseBodyTransferedParams(), response);

        }else {

    bizResult = BizResult.create(null,false,"9999","assertExpected返回错误");

        }

    }catch (NullPointerException e) {

    bizResult = BizResult.create(e,false,"9999","获取response实体时出现Exception");

    }

    finally {

    try {

    //关闭连接

            response.close();

            client.close();

        }catch (Exception e) {

    bizResult = BizResult.create("BOOM!!!",true,"1000","HTTPClient没有关闭");

        }

    if (bizResult ==null) {

    bizResult = BizResult.create("OK",true,"1000","接口测试通过");

        }

    }

    return bizResult;

    函数的逻辑十分清晰

    - 先执行请求

    - 断言返回值是否符合预期

    - 满足断言,则处理Response, 获取响应对象中部分参数的值

    executeEncapsulation代码如下

    //参数替换

    BizResult replaceHeaderParamsResult = replaceParams(httpInterfaceCaseDO.getRequestHeader());

    if (! replaceHeaderParamsResult.isSuccess()) {

    return replaceHeaderParamsResult;

    }else {

    httpInterfaceCaseDO.setRequestHeader(replaceHeaderParamsResult.getData().toString());

    }

    BizResult replaceBodyParamsResult = replaceParams(httpInterfaceCaseDO.getRequestBody());

    if (! replaceBodyParamsResult.isSuccess()) {

    return replaceBodyParamsResult;

    }else {

    httpInterfaceCaseDO.setRequestBody(replaceBodyParamsResult.getData().toString());

    }

    //参数校验

    BizResult initResult = init(httpInterfaceCaseDO);

    if (! initResult.isSuccess()) {

    return initResult;

    }

    return executeHttpRequest(httpInterfaceCaseDO);

    替换请求头和请求体的值,再进行值检验

    replaceParams代码如下

    if (StringUtils.isNoneBlank(str)) {

    JSONObject bodyObject = JSON.parseObject(str);

                for (String key:

    bodyObject.keySet()) {

    String keyget = (String) bodyObject.get(key);

                    if (keyget.startsWith("$")) {

    String replacekey = keyget.substring(keyget.indexOf("{") +1, keyget.indexOf("}")).trim();

                        if (StringUtils.isNoneBlank(replacekey)) {

    String value = (String)ReplaceMap.get(replacekey);

                            if (StringUtils.isBlank(value)) {

    return BizResult.create(null,false,"9999","ReplaceMap取值异常");

                            }

    //                        替换请求体内的变量

                            bodyObject.replace(key, value);

                        }else {

    return BizResult.create(null,false,"9999","ReplaceMap取值异常");

                        }

    }

    }

    }

    return BizResult.create(str,true,"1000","替换RequestBody里面的转义字符成功");

    这里是直接传待转换字符串进来,这个字符串为了方便默认是JSONString,然后就是正则处理下。

    这里要注意的是

    String value = (String)ReplaceMap.get(replacekey);

    因为会有其他测试人员在接口测试时,打错了变量名,这样的场景是我们要去避免的

    init代码如下

        if (! checkParams(httpInterfaceCaseDO)) {

    return BizResult.create("CheckParameters not pass",false,"9999","Request参数缺失");

    }

    //RequestMethod检验

    if (! (httpInterfaceCaseDO.getRequestMethod().toUpperCase().contentEquals(HttpEnum.GET ) || httpInterfaceCaseDO.getRequestMethod().toUpperCase().contentEquals(HttpEnum.POST ))) {

    return BizResult.create("RequestMethod异常",false,"9999","RequestMethod异常");

    }

    if (StringUtils.isNotEmpty(httpInterfaceCaseDO.getDataFormat()) && StringUtils.isNotBlank(httpInterfaceCaseDO.getDataFormat().trim())) {

    if (! (httpInterfaceCaseDO.getDataFormat().toUpperCase().contentEquals(HttpEnum.STRING) || httpInterfaceCaseDO.getDataFormat().toUpperCase().contentEquals(HttpEnum.JSON) || httpInterfaceCaseDO.getDataFormat().toUpperCase().contentEquals(HttpEnum.FORM) || httpInterfaceCaseDO.getDataFormat().toUpperCase().contentEquals(HttpEnum.MEDIA))) {

    //如果没有参数类型,默认设置为Srting

            httpInterfaceCaseDO.setDataFormat(HttpEnum.STRING);

        }

    }

    getSessionId(httpInterfaceCaseDO);

    return BizResult.create("continue",true,"6666","初始化测试数据成功");

    getSessionId代码如下

        String sessionId ="";

            String body ="";

            try {

    if (context ==null) {

    log.info("context为空");

                }

    List listOfCookies =context.getCookieStore().getCookies();

                for (Cookie cookie:

    listOfCookies) {

    if (“这里不给看哦”.equals(cookie.getName())) {

    return BizResult.create("", true, "1000", "已有sessionId,直接通过");

                    }

    }

    }catch (Exception e) {

    log.info("日常没登陆");

            }

    if (! httpInterfaceCaseDO.getRequestUrl().contains("login")) {

    return BizResult.create(null, true, "9999", "未登录");

            }else {

    //涉及我司有关内容,已删除

    BizResult executeResult = executeHttpRequest(httpInterfaceCaseDO);

                if (! executeResult.isSuccess()) {

    return executeResult;

                }

    CloseableHttpResponse response = (CloseableHttpResponse) executeResult.getData();

                if (response.getStatusLine().getStatusCode() != HttpEnum.STATUS_OK) {

    return BizResult.create(null, false, "9999", "请求失败");

                }

    }

    return BizResult.create(sessionId, true, "1000", "请求成功");

    这里主要依赖了HTTPContext保持连接的特性,在单线程内,只要不close掉的话,会一直存储Cookie和其他需要的值

    executeHttpRequest代码如下

        CloseableHttpResponse response =null;

            HttpEntity entity =null;

            //请求协议

            String requestType = httpInterfaceCaseDO.getRequestUrl().substring(0, httpInterfaceCaseDO.getRequestUrl().indexOf(":", 1)).trim();

    //        实例化httpclient

            BizResult requestResult = switchType(requestType);

            if (!requestResult.isSuccess()) {

    return requestResult;

            }

    //        判断请求类型

            try {

    switch (httpInterfaceCaseDO.getRequestMethod().toUpperCase()) {

    case HttpEnum.GET:

    HttpGet httpGet =null;

    //              判断是否有请求体

                        if (StringUtils.isNotEmpty(httpInterfaceCaseDO.getRequestBody()) && StringUtils.isNotBlank(httpInterfaceCaseDO.getRequestBody().trim())) {

    String body = httpInterfaceCaseDO.getRequestBody().trim();

    //                    url为转换后的请求体

                            StringBuilder url =new StringBuilder();

    //                    判断请求体是否是json格式的数据

                            if (body.startsWith("{")) {

    JSONObject jsonObject = JSON.parseObject(body);

                                for (String key :

    jsonObject.keySet()) {

    if (StringUtils.isNotEmpty(url)) {

    url.append("&");

                                    }

    url.append(String.format("%s?%s", key, jsonObject.getString(key)));

                                }

    }

    //                          有请求体的GET

                            httpGet =new HttpGet(String.format("%s?%s", httpInterfaceCaseDO.getRequestUrl(), url.toString()));

                        }else {

    //                        无请求体的GET

                            httpGet =new HttpGet(httpInterfaceCaseDO.getRequestUrl());

                        }

    if (StringUtils.isNoneBlank(httpInterfaceCaseDO.getRequestHeader())) {

    JSONObject headerObject = JSON.parseObject(httpInterfaceCaseDO.getRequestHeader());

                            for (String key :

    headerObject.keySet()) {

    httpGet.addHeader(key, (String) headerObject.get(key));

                            }

    }

    for (Header header :

    defaultHeader()) {

    httpGet.addHeader(header);

                        }

    //执行http get请求

                        response =client.execute(httpGet, context);

    break;

                    case HttpEnum.POST:

    HttpPost httpPost =new HttpPost(httpInterfaceCaseDO.getRequestUrl());

                        if (StringUtils.isEmpty(httpInterfaceCaseDO.getDataFormat())) {

    //                  POST方式需要DataFormat字段,无此字段则抛出异常

                            throw new ValueException("POST没有DataFormat字段");

                        }

    // 创建请求参数

                        switch (httpInterfaceCaseDO.getDataFormat().toUpperCase()) {

    case HttpEnum.STRING:

    entity =new StringEntity(httpInterfaceCaseDO.getRequestBody(), "utf-8");

    break;

                            case HttpEnum.FORM:

    List body =new ArrayList();

                                JSONObject jsonObject = JSON.parseObject(httpInterfaceCaseDO.getRequestBody());

                                for (String key :

    jsonObject.keySet()) {

    body.add(new BasicNameValuePair(key, jsonObject.getString(key)));

                                }

    entity =new UrlEncodedFormEntity(body, "utf-8");

    break;

    //                      这里暂时不动,考虑下Entity的类型

                            case HttpEnum.MEDIA:

    //获取分隔符

                                String[] array = httpInterfaceCaseDO.getRequestHeader().split("=");

                                String bound = array[1].substring(1, array[1].lastIndexOf("\""));

                                //添加分割线

    //                      entity = new MultipartRequestEntity();

                                break;

                            default:

    break;

                        }

    httpPost.setEntity(entity);

                        if (StringUtils.isNoneBlank(httpInterfaceCaseDO.getRequestHeader())) {

    JSONObject headerObject = JSON.parseObject(httpInterfaceCaseDO.getRequestHeader());

                            for (String key :

    headerObject.keySet()) {

    httpPost.addHeader(key, (String) headerObject.get(key));

                            }

    }

    for (Header header :

    defaultHeader()) {

    httpPost.addHeader(header);

                        }

    //执行http post请求

                        response =client.execute(httpPost, context);

    break;

                    default:

    break;

                    }

    }catch(IOException | NullPointerException e){

    return BizResult.create(e, false, "9999", "请求异常 -  " + httpInterfaceCaseDO.getRequestMethod().toUpperCase());

            }

    return BizResult.create(response, true, "1000", "请求成功");

    这块代码也是我负责的项目中最长最重要的一块,你们可以看到我POST的MEDIA方式,是还没写完的,不好意思,写到一半的时候,被告知我司的接口需要用到该场景的次数极少,故不了了之,代码长就长在对String的处理,其实像

    JSONObject jsonObject = JSON.parseObject(body);

    for (String key :

    headerObject.keySet()) {

    httpPost.addHeader(key, (String) headerObject.get(key));

    }

    这种代码是可以的整合的,但写完就不想动了。。。

    简书不是支持MarkDown的么,写完一发,看到格式不对,真是哔到gou了

    暂时先到这,再熬夜怕是要变强了😭

    相关文章

      网友评论

          本文标题:基础的HTTPClient搭建注意事项(中)

          本文链接:https://www.haomeiwen.com/subject/lhpqoxtx.html