alexpdh's blog

记一次http接口调试问题

  在开发工程中,我们经常会遇到和其它第三方厂家有接口数据来往的情况。这是一次我们作为客户端
去获取另一个厂家推流的直播地址的接口,这个接口情况有些不一样,我们需要在一个接口中封装两次http请求,大概场景是这样的:

第一次调用方式是POST,第二次是Get,第一次调用会获取到一个地址,返回结果类似这样的:

1
2
3
4
5
6
7
{
"resultcode": "0",
"desc": "配置url成功",
"playurl": "http://xxx.xxx.cn:1100/pushUserInfo/v1/7+MbU0JGqdzxR4r9WppYdwgiEBj1vS3sjmIJGKzyd1Uo7Aiw8n5TGdmmh+6t7v1caKu15I+WJKsQRZzQ3rtT519E0R9pO4XHygB+bx0irIFIhuLVREDEOS0+OKpwcFWrIVRTurT8nTEdB8LACa5KifWfUPB6Emm5grPgROocpTZIWoo7c78ezILqwAMZ4flghHLSoucOW6S/OO86fUfNxg==/3006686669_52.mp4.m3u8?ec=1/type=aepadapter/fixed/ip/hls/config
2016-8-25 18-441"
}

这里获取到接口返回一个带参数的地址,这里注意一下,这个地址里有些特殊符号,如:下划线、等号之类的等等。我们还需要将返回的这个带参数的URL地址作为第二个请求的URL,并携带上第二个请求播放接口要求的请求参数使用get方式调用接口请求从而获取到一个重定向的地址,请求地址类似这样的:

1
2
http://xxx.xxx.com/pushUserInfo/v1/7Jo8ty86AUKmr6fTuRYQ6Ylf+YaMXYF6GTPPWPchbvvIMG9MADvMOQtk9pOF0VjDSBuMxDZ4TPap2G5uhoCuurjoLwyNhbaPxV0T4XJFUK4CRUlwskU5eA4ImCjdv06plhYlvEeHW+IEASnEbvRhnuwJSXJUDfm8XTScBLnyuDEyTmPlrZTRwoUqFH7Bri8i0pW1M0OlpjB8fzWjTudRiA==/3006686669_52.mp4.m3u8?ec=1/type=aepadapter/fixed/ip/hls/config0&Id_type=1&userid=15000000000&ipaddress=10.1.1.1 HTTP/1.1

http返回码应该是302,这个地址才是真正的播放地址,其实是一个m3u8的播放流。对方通过这样的一个地址进行推流播放。很快这个接口封装好了,自己写了个单元测试进行调用测试;在做单元测试的过程中发现最终的返回码是200,而且响应的报文是空的,什么信息都没有。正常应该是返回302,
单独测试第一个接口的时候响应是正常的,测试第二个的时候出问题了,反复确认封装的请求参数是没有问题的,开始怀疑是对方响应有问题。后来我单独用第一个返回的地址带上参数在浏览器中请求是可以的,于是知道大概是URL被转码了的原因,因为第一个接口返回的地址是带了参数的,如上面参数里有很多特殊字符。我在请求的时候自己封装了一个httpclient工具类,里面有封装的带参数的get方法是这样写的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static String httpGetRequest(String url, Map<String, Object> params){
String result=EMPTY_STR;
URIBuilder ub = new URIBuilder();
ub.setPath(url);
ArrayList<NameValuePair> pairs = covertParams2NVPS(params);
ub.setParameters(pairs);
try{
HttpGet httpGet = new HttpGet(ub.build());
result = getResult(httpGet);
}catch(URISyntaxException e){
e.printStackTrace();
}
return result;
}

这里在构造请求时使用的是 java.net.URI 来构造的,而经过查询,从jdk的一个bug回复中知道:
JDK-8132508 : Bug JDK-8029354 reproduces with underscore in hostname

1
2
3
RFC 952 disallows _ underscores in hostnames. So, this is not a bug. I also haven't been able to find examples of actual usage.
So, unless a particularly compelling case can be made, I'm closing as not a bug.

说明了java.net.URI 的域名只能由 字母 (A-Z), 数字(0-9), 减号 (-), 和 点 (.) 组成。也就是说 java.net.URI 验证了 hostname。同时也看到了在 java.net.URL 中不会做这个验证。所以问题找到了,所以我们把这个方法换成其它方式来构造就正常返回了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private static String createParamUrl(String url, Map<String, Object> params) {
Iterator<String> it = params.keySet().iterator();
StringBuilder sb = new StringBuilder();
boolean isIncludeQuestionMark =url.contains("?");
if (!isIncludeQuestionMark) {
sb.append("?");
}
while (it.hasNext()) {
String key = it.next();
String value = (String) params.get(key);
sb.append("&");
sb.append(key);
sb.append("=");
sb.append(value);
}
url += sb.toString();
return url;
}

赞同提交bug的网友的意见,这样会隐藏很多的坑。为什么一个验证了域名一个却不做验证。我们也看到bug提交之后得到回复这不是一个bug。


参考文献

alexpdh wechat
欢迎扫一扫关注 程序猿pdh 公众号!