如何保存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”,禁止第三方(腾讯云除外)转载、发表。
技术类文章精选
- java一行代码打印心形
- Linux性能监控软件netdata中文汉化版
- 性能测试框架第二版
- 如何在Linux命令行界面愉快进行性能测试
- 图解HTTP脑图
- 将swagger文档自动变成测试代码
- 五行代码构建静态博客
- 基于java的直线型接口测试框架初探
- Selenium 4.0 Alpha更新日志
- Selenium 4.0 Alpha更新实践
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南