代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
public
static
String
getHttpResponse4Get()
{
String
url = “http:
//www.tmall.com/test.do?id=123”;
GetMethod httpGet =
new
GetMethod(url);
httpGet.addRequestHeader(
"content-type"
,
"text/html; charset=gbk"
);
httpGet.getParams().setParameter(
"http.socket.timeout"
,
20000
);
try
{
// 设置成了默认的恢复策略,在发生异常时候将自动重试3次,在这里你也可以设置成自定义的恢复策略
httpGet.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
new
DefaultHttpMethodRetryHandler());
if
(httpClient.executeMethod(httpGet) != HttpStatus.SC_OK) {
System.out.println(
"httpGet(\""
+ url +
"\") failed: \n"
+ httpGet.getStatusLine());
return
null
;
}
return
httpGet.getResponseBodyAsString();
}
catch
(Exception e) {
System.out.println(
"httpGet(\""
+ url +
"\") failed: \n"
+ e.getMessage());
return
null
;
}
finally
{
httpGet.releaseConnection();
httpClient =
null
;
}
}
|
注意点:
1、传入参数值(或者参数串)需要进行encode,虽然httpClient中是有用URLCodec.encodeUrl()进行encode,但我实验发现,和URLEncoder.encode()进行encode的结果还是有区别,会对最终响应有影响,所以建议自行encode;
2、需要判断请求返回的状态码是否为200以后获取到的响应才是可靠的;
3、最终要释放掉链接,做好收尾工作。
代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
public
static
String
getHttpResponse4Post()
{
try
{
HttpClient client =
new
DefaultHttpClient();
HttpPost request =
new
HttpPost(
"http://www.tmall.com/test.do"
);
//使用NameValuePair来保存要传递的Post参数
List
new
ArrayList
//添加要传递的参数
postParameters.add(
new
BasicNameValuePair(
"id"
,
"12345"
));
postParameters.add(
new
BasicNameValuePair(
"username"
,
"dave"
));
//实例化UrlEncodedFormEntity对象
UrlEncodedFormEntity formEntity =
new
UrlEncodedFormEntity(
postParameters);
//使用HttpPost对象来设置UrlEncodedFormEntity的Entity
request.setEntity(formEntity);
HttpResponse response = client.execute(request);
if
(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String
s = EntityUtils.toString(response.getEntity(),
"utf-8"
);
System.out.println(s);
System.out.println(
"请求正常,结束http请求"
);
return
s;
}
}
catch
(Exception e) {
System.out.println(
"请求发生异常,异常信息抛出"
);
e.printStackTrace();
}
finally
{
httpClient.getConnectionManager().shutdown();
}
return
""
;
}
|
要将在daily下运行的http接口测试脚本放到线上运行,需要做如下一些操作:
1、 建立一个真实的登录session:发送post请求到:https://login.taobao.com/member/login.jhtml
2、 然后发送get请求到http://i.taobao.com/my_taobao.htm从缓存中同步一次cookie
3、 通过this.httpClientLogin.getState().getCookies();获取到cookie信息,然后解析到_tb_token_的值
4、 把这个_tb_token_这个参数和值附加到测试请求的url中,通过get方式进行请求即可
5、 注意:在登录的post参数设置时,需要将字符集设为:GBK
1
|
postMethod.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET,
"GBK"
);
|
如果改为utf-8或者不set此param就可能导致获取的cookie值不足的问题
(本部分感谢浣碧同学的悉心指点!)
为什么url需要encode以后才能发送,是因为URL需要转化为ASCII字符集才能在被HTTP协议使用。ASCII字符集7位的字符集,包含128个字符,其中常见的有数字1-9,还有a-zA-Z以及一些特殊字符。当URL中包含非ASCII字符集的字符的时候,就需要encode为ASCII字符集,以便通过HTTP协议发送请求
Java中进行URL Encode和Decode的方法是:
1
2
3
|
URLEncoder.encode(valueOfUrlParam,
"UTF-8"
);
URLDecoder.decode(urlParamStr,
"UTF-8"
);
|
两个类都来自java.net的包,平时可以使用online的encode/decode网站进行操作
这里需要注意的是:
http://www.tmall.com/test.do?id=123,234,正确的encode以后的url为:
http://www.tmall.com/test.do?id%3d123%2c234 或者:
http://www.tmall.com/test.do?id=123%2c234
问题场景:在服务端应用程序里通常会有这样的片段:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public
static
Long getLoginUserId(TurbineRunData rundata) {
String
userId = (
String
) rundata.getRequest().getSession().getAttribute(
SessionKeeper.ATTRIBUTE_USER_ID_NUM);
if
(StringUtils.isNumeric(userId)) {
return
Long.parseLong(userId);
}
return
null
;
}
|
1
2
3
4
5
6
7
8
9
|
if
(userId==
null
|| userId <=
0
) {
result.setSuccess(
false
);
result.setErrorCode(MallBrandResultCode.USER_NOT_LOGIN);
result.setErrorMsg(
"参数user_id缺失"
);
}
|
如果webx不能从session中获取到userID,那就会被业务逻辑控制住,不能继续往下走,解决办法有两个:
l 往session里塞userId
要实现这种方案,首先需要创建一个真实daily下用户登录的session,由于是在daily下,还需要解决安全认证的问题,这样便能解决这个问题。但明显这样做的成本太高,而且不是很必要。
l 通过get参数mock掉这段代码逻辑
和开发约定一个参数和参数值,在程序中判断如果有这个参数值则直接返回一个指定的userId。
1
|
boolean test = rundata.getParameters().getBoolean(
"test"
,
false
);
|
b) 压缩mock
为了防止前端发送的json数据时http的get请求超长,前后端开发通过7zip进行压缩,但httpClient认为这样的压缩过的请求是BadRequest,所以只能试图把请求换成post,同时把解压缩的逻辑mock掉,以便于daily下的接口测试。具体详见:《http接口测试中有关URL长度限制的问题(Maximum URL Length)》
c) csrf控制mock
代码中为了防止csrf攻击,都会加入csrf的控制模块,在daily下可以直接让开发把这段逻辑注释掉,但如果脚本还要在系统上线后回归,那就需要和开发一起把这段逻辑mock掉,以简化测试应用的复杂度,降低测试脚本开发难度。