如何保存HTTPrequestbase和CloseableHttpResponse


在測試過程中,有一個重要的工作就是保存記錄“現場”,以方便開發人員更快發現BUG解決問題。在接口測試中更是如此,如果開發人員能夠根據BUG的信息直接復現請求,是一件很方便的事情。為此我想了一個再框架中增加保存HTTPrequestbase和CloseableHttpResponse兩個對象的功能,其中主要是HTTPrequestbase的信息,CloseableHttpResponse以響應內容為主,因為每次請求我都會把必要信息(host,API,HTTP code,響應code,響應時間等等記錄)。

下面是更新過的funrequest類的代碼,更新內容時后面幾個靜態方法:

package com.fun.frame.httpclient

import com.fun.base.bean.RequestInfo
import com.fun.base.exception.RequestException
import com.fun.config.HttpClientConstant
import com.fun.config.RequestType
import com.fun.frame.Save
import com.fun.utils.Time
import net.sf.json.JSONObject
import org.apache.commons.lang3.StringUtils
import org.apache.http.Header
import org.apache.http.HttpEntity
import org.apache.http.client.methods.HttpPost
import org.apache.http.client.methods.HttpRequestBase
import org.apache.http.util.EntityUtils
import org.slf4j.Logger
import org.slf4j.LoggerFactory

/**
 * 重寫FanLibrary,使用面對對象思想
 */
public class FunRequest extends FanLibrary implements Serializable, Cloneable {

    private static final long serialVersionUID = -4153600036943378727L;

    static Logger logger = LoggerFactory.getLogger(FunRequest.class)

    /**
     * 請求類型,true為get,false為post
     */

    RequestType requestType

    /**
     * 請求對象
     */

    HttpRequestBase request

    /**
     * host地址
     */

    String host = EMPTY

    /**
     * 接口地址
     */

    String apiName = EMPTY

    /**
     * 請求地址,如果為空則由host和apiname拼接
     */

    String uri = EMPTY

    /**
     * header集合
     */

    List<Header> headers = new ArrayList<>()

    /**
     * get參數
     */

    JSONObject args = new JSONObject()

    /**
     * post參數,表單
     */

    JSONObject params = new JSONObject()

    /**
     * json參數
     */

    JSONObject json = new JSONObject()

    /**
     * 響應,若沒有這個參數,從將funrequest對象轉換成json對象時會自動調用getresponse方法
     */

    JSONObject response = new JSONObject()

    /**
     * 構造方法
     *
     * @param requestType
     */
    private FunRequest(RequestType requestType) {
        this.requestType = requestType
    }

    /**
     * 獲取get對象
     *
     * @return
     */
    static FunRequest isGet() {
        new FunRequest(RequestType.GET)
    }

    /**
     * 獲取post對象
     *
     * @return
     */
    static FunRequest isPost() {
        new FunRequest(RequestType.POST)
    }

    /**
     * 設置host
     *
     * @param host
     * @return
     */
    FunRequest setHost(String host) {
        this.host = host
        this
    }

    /**
     * 設置接口地址
     *
     * @param apiName
     * @return
     */
    FunRequest setApiName(String apiName) {
        this.apiName = apiName
        this
    }

    /**
     * 設置uri
     *
     * @param uri
     * @return
     */
    FunRequest setUri(String uri) {
        this.uri = uri
        this
    }

    /**
     * 添加get參數
     *
     * @param key
     * @param value
     * @return
     */
    FunRequest addArgs(Object key, Object value) {
        args.put(key, value)
        this
    }

    /**
     * 添加post參數
     *
     * @param key
     * @param value
     * @return
     */
    FunRequest addParam(Object key, Object value) {
        params.put(key, value)
        this
    }

    /**
     * 添加json參數
     *
     * @param key
     * @param value
     * @return
     */
    FunRequest addJson(Object key, Object value) {
        json.put(key, value)
        this
    }

    /**
     * 添加header
     *
     * @param key
     * @param value
     * @return
     */
    FunRequest addHeader(Object key, Object value) {
        headers << getHeader(key.toString(), value.toString())
        this
    }

    /**
     * 添加header
     *
     * @param header
     * @return
     */
    public FunRequest addHeader(Header header) {
        headers.add(header)
        this
    }

    /**
     * 批量添加header
     *
     * @param header
     * @return
     */
    FunRequest addHeader(List<Header> header) {
        header.each {h -> headers << h}
        this
    }

    /**
     * 增加header中cookies
     *
     * @param cookies
     * @return
     */
    FunRequest addCookies(JSONObject cookies) {
        headers << getCookies(cookies)
        this
    }

    FunRequest setHeaders(List<Header> headers) {
        this.headers.addAll(headers)
        this
    }

    FunRequest setArgs(JSONObject args) {
        this.args.putAll(args)
        this
    }

    FunRequest setParams(JSONObject params) {
        this.params.putAll(params)
        this
    }

    FunRequest setJson(JSONObject json) {
        this.json.putAll(json)
        this
    }

    /**
     * 獲取請求響應,兼容相關參數方法,不包括file
     *
     * @return
     */
    JSONObject getResponse() {
        response = response.isEmpty() ? getHttpResponse(request == null ? getRequest() : request) : response
        response
    }


    /**
     * 獲取請求對象
     *
     * @return
     */
    HttpRequestBase getRequest() {
        if (request != null) request;
        if (StringUtils.isEmpty(uri))
            uri = host + apiName
        switch (requestType) {
            case RequestType.GET:
                request = FanLibrary.getHttpGet(uri, args)
                break
            case RequestType.POST:
                request = !params.isEmpty() ? FanLibrary.getHttpPost(uri + changeJsonToArguments(args), params) : !json.isEmpty() ? getHttpPost(uri + changeJsonToArguments(args), json.toString()) : getHttpPost(uri + changeJsonToArguments(args))
                break
        }
        for (Header header in headers) {
            request.addHeader(header)
        }
        logger.debug("請求信息:{}", new RequestInfo(this.request).toString())
        request
    }

    @Override
    FunRequest clone() {
        def fun = new FunRequest()
        fun.setRequest(cloneRequest(getRequest()))
        fun
    }

    @Override
    public String toString() {
        return "{" +
                "requestType='" + requestType.getName() + '\'' +
                ", host='" + host + '\'' +
                ", apiName='" + apiName + '\'' +
                ", uri='" + uri + '\'' +
                ", headers=" + header2Json(headers).toString() +
                ", args=" + args.toString() +
                ", params=" + params.toString() +
                ", json=" + json.toString() +
                ", response=" + getResponse().toString() +
                '}';
    }


/**
 * 從requestbase對象從初始化funrequest
 * @param base
 * @return
 */
    static FunRequest initFromRequest(HttpRequestBase base) {
        FunRequest request = null;
        String method = base.getMethod();
        RequestType requestType = RequestType.getRequestType(method);
        String uri = base.getURI().toString();
        List<Header> headers = Arrays.asList(base.getAllHeaders());
        if (requestType == requestType.GET) {
            request = FunRequest.isGet().setUri(uri).setHeaders(headers);
        } else if (requestType == RequestType.POST || requestType == RequestType.FUN) {
            HttpPost post = (HttpPost) base;
            HttpEntity entity = post.getEntity();
            String value = entity.getContentType().getValue();
            String content = null;
            try {
                content = EntityUtils.toString(entity);
            } catch (IOException e) {
                logger.error("解析響應失敗!", e)
                fail();
            }
            if (value.equalsIgnoreCase(HttpClientConstant.ContentType_TEXT.getValue()) || value.equalsIgnoreCase(HttpClientConstant.ContentType_JSON.getValue())) {
                request = FunRequest.isPost().setUri(uri).setHeaders(headers).setJson(JSONObject.fromObject(content));
            } else if (value.equalsIgnoreCase(HttpClientConstant.ContentType_FORM.getValue())) {
                request = FunRequest.isPost().setUri(uri).setHeaders(headers).setParams(getJson(content.split("&")));
            }
        } else {
            RequestException.fail("不支持的請求類型!");
        }
        return request;
    }


/**
 * 拷貝HttpRequestBase對象
 * @param base
 * @return
 */
    static HttpRequestBase cloneRequest(HttpRequestBase base) {
        return initFromRequest(base).getRequest()
    }

/**
 * 保存請求和響應
 * @param base
 * @param response
 */
    public static void save(HttpRequestBase base, JSONObject response) {
        FunRequest request = initFromRequest(base)
        request.setResponse(response);
        Save.info("/request/" + Time.getDate().substring(8) + SPACE_1 + request.getUri().replace(OR, PART), request.toString());
    }

}

然后在框架是添加一個key來控制是否保存響應,然后調用保存方法:
if (SAVE_KEY) FunRequest.save(request, res);
其中,res是響應內容,已經解析為json格式,對於非json格式響應做了兼容。同事在保存路徑和保存量也做配置初始化的過程中做了校驗,這個太簡單就不發了。
其中一個header2Json方法是為了解決保存header時候不必須信息太多的問題,內容如下:

    /**
     * 將header轉成json對象
     *
     * @param headers
     * @return
     */
    public static JSONObject header2Json(List<Header> headers) {
        JSONObject h = new JSONObject();
        headers.forEach(x -> h.put(x.getName(), x.getValue()));
        return h;
    }

這個是內容:
{requestType='post', host='', apiName='', uri='https://cn.bing.com/search', headers={"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"}, args={}, params={"q":"fun"}, json={}, response={"3242":"234"}}

這樣做的好處就是,如果想復現某個出現問題的request,直接從文件中讀取保存的request信息,借由funrequest類對象即可復現這個請求,還可以跟記錄的response做對比。


  • 鄭重聲明:文章首發於公眾號“FunTester”,禁止第三方(騰訊雲除外)轉載、發表。

技術類文章精選

非技術文章精選


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM