一次http接口调试问题

来源:互联网 发布:淘宝公主裙 编辑:程序博客网 时间:2024/05/16 19:40

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

第一次调用方式是POST,第二次是Get,第一次调用会获取到一个地址,返回结果类似这样的 {“resultcode”:”0”,”desc”:”配置url成功”,”playurl”:” http://aep.cmvideo.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方式调用接口请求从而获取到一个重定向的地址,请求地址类似这样的:http://aep.sdp.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方法是这样写的:

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回复中知道:
* RFC 952 disallows _ underscores in hostnames. So, this is not a bug.
RFC 952 说明了java.net.URI 的域名只能由 字母 (A-Z), 数字(0-9), 减号 (-), 和 点 (.) 组成。也就是说 java.net.URI 验证了 hostname。同时也看到了在 java.net.URL 中不会做这个验证。所以问题找到了,所以我们把这个方法换成其它方式来构造就正常返回了。

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。

最后附上封装的httpclient代码一份:

package com.richinfo.util.http;import java.util.Map;import java.util.Iterator;import java.io.IOException;import java.util.ArrayList;import org.apache.http.Header;import org.apache.http.HttpEntity;import org.apache.http.HttpStatus;import org.apache.http.NameValuePair;import org.apache.http.ParseException;import com.richinfo.util.json.JsonUtil;import org.apache.http.util.EntityUtils;import org.apache.http.entity.StringEntity;import java.io.UnsupportedEncodingException;import org.apache.http.client.methods.HttpGet;import org.apache.http.client.methods.HttpPost;import org.apache.http.impl.client.HttpClients;import org.apache.http.message.BasicNameValuePair;import org.apache.http.client.config.RequestConfig;import java.nio.charset.UnsupportedCharsetException;import org.apache.http.client.ClientProtocolException;import org.apache.http.client.methods.HttpRequestBase;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.client.entity.UrlEncodedFormEntity;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;/** *  *function: APACHE HTTP-CLIENT 封装工具 * */public class HttpClientUtil {    private static PoolingHttpClientConnectionManager cm;    private static String EMPTY_STR = "";    private static String UTF_8 = "UTF-8";    private static final int  timeout =15000;    private static final boolean defaultRedirectsEnabled = false;    // 整个连接池最大连接数    private static final int  maxTotal =200;    // 每路由最大连接数,默认值是2    private static final int  defaultMaxPerRoute=maxTotal;    /**     * function:发送get请求     * @param url 请求地址     * @return String     */    public static String httpGetRequest(String url) {        HttpGet httpGet = new HttpGet(url);        return getResult(httpGet);    }    /**     * function:发送get请求     * @param  url 请求地址     * @param  headers 头信息     * @return String     */    public static String httpGetRequestWithHeaders(String url, Map<String, Object> headers){        HttpGet httpGet = new HttpGet(url);        for (Map.Entry<String, Object> param : headers.entrySet()) {            httpGet.addHeader(param.getKey(), String.valueOf(param.getValue()));        }        return getResult(httpGet);    }    /**     * function:发送get请求     * @param url 请求地址     * @param headers 头信息     * @param params 参数     * @return String     */    public static String httpGetRequest(String url, Map<String, Object> headers, Map<String, Object> params){        String result=EMPTY_STR;        HttpGet httpGet = new HttpGet(createParamUrl(url,params));        for (Map.Entry<String, Object> param : headers.entrySet()) {                httpGet.addHeader(param.getKey(), String.valueOf(param.getValue()));            }         result=getResult(httpGet);         return result;    }    /**     * function:发送get请求     * @param  url 请求地址     * @param  headers 头信息     * @return String      */    public static String httpGetRequestWithParams(String url, Map<String, Object> params){        HttpGet httpGet = new HttpGet(createParamUrl(url,params));        return getResult(httpGet);    }    /**     * function:创建带参数的URL     * @param url 无参URL     * @param params 参数     * @return String 带参数URL     */    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;      }      /**     * function:post请求访问     * @param url 请求地址     * @return String      */    public static String httpPostRequest(String url) {        HttpPost httpPost = new HttpPost(url);        return getResult(httpPost);    }    /**     * function:post请求访问     * @param url 地址     * @param params 参数     * @return String      *     */    public static String httpPostRequest(String url, Map<String, Object> params){        HttpPost httpPost = new HttpPost(url);        ArrayList<NameValuePair> pairs = covertParams2NVPS(params);        try {            httpPost.setEntity(new UrlEncodedFormEntity(pairs, UTF_8));        } catch (UnsupportedEncodingException e) {            e.printStackTrace();        }        return getResult(httpPost);    }    /**     * function:post请求访问     * @param url 地址     * @param headers   头信息     * @param params 参数     * @return  String     *      */    public static String httpPostRequest(String url, Map<String, Object> headers, Map<String, Object> params) {        HttpPost httpPost = new HttpPost(url);        for (Map.Entry<String, Object> headerParam : headers.entrySet()) {            httpPost.addHeader(headerParam.getKey(), String.valueOf(headerParam.getValue()));        }        ArrayList<NameValuePair> pairs = covertParams2NVPS(params);        try {            httpPost.setEntity(new UrlEncodedFormEntity(pairs, UTF_8));        } catch (UnsupportedEncodingException e) {            e.printStackTrace();        }        return getResult(httpPost);    }    /**     * function:post以JSON格式发送     * @param url 地址     * @param headers   头信息     * @param params 参数     * @return  String     *      */    public static String httpPostRequestByJson(String url, Map<String, Object> headers, Map<String, Object> params) {        HttpPost httpPost = new HttpPost(url);        for (Map.Entry<String, Object> headerParam : headers.entrySet()) {            httpPost.addHeader(headerParam.getKey(), String.valueOf(headerParam.getValue()));        }        try {            String json = JsonUtil.readMaptoJson(params);            httpPost.setEntity(new StringEntity(json, "UTF-8"));        } catch (UnsupportedCharsetException e) {            e.printStackTrace();        }        return getResult(httpPost);    }    /**     * function:把参数转换为名值对数组     * @param params  参数     * @return  ArrayList<NameValuePair>     */    private static ArrayList<NameValuePair> covertParams2NVPS(Map<String, Object> params) {        ArrayList<NameValuePair> pairs = new ArrayList<NameValuePair>();        for (Map.Entry<String, Object> param : params.entrySet()) {            pairs.add(new BasicNameValuePair(param.getKey(), String.valueOf(param.getValue())));        }        return pairs;    }    /**     * 执行 HTTP请求     * @param request     * @return String 若重定向返回重定向地址     */    private static String getResult(HttpRequestBase request) {        String result=EMPTY_STR;        request.setConfig(createConfig(timeout, defaultRedirectsEnabled));        CloseableHttpClient httpClient = getHttpClient();        try {            CloseableHttpResponse response = httpClient.execute(request);            if (isRedirected(response)){                result=getRedirectedUrl(response);            }else{                result=getEntityData(response);            }        } catch (ClientProtocolException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }         return result;    }    /**     * function:创建HTTP请求配置     * @param timeout 超时     * @param redirectsEnabled 是否开启重定向     * @return RequestConfig     */    private static RequestConfig createConfig(int timeout, boolean redirectsEnabled) {        return RequestConfig.custom()            .setSocketTimeout(timeout)            .setConnectTimeout(timeout)            .setConnectionRequestTimeout(timeout)            .setRedirectsEnabled(redirectsEnabled)            .build();    }    /**     * 通过连接池获取HttpClient     *      * @return     */    private static CloseableHttpClient getHttpClient() {        init();        return HttpClients.custom().setConnectionManager(cm).build();    }    /**     *      * function:初始化方法     *      */    private static void init() {        if (cm == null) {            cm = new PoolingHttpClientConnectionManager();            cm.setMaxTotal(maxTotal);            cm.setDefaultMaxPerRoute(defaultMaxPerRoute);        }    }    /**     * function:判断发送请求是否重定向跳转过     * @param response 请求响应     * @return boolean      */    private static boolean  isRedirected(CloseableHttpResponse response){        int statusCode = response.getStatusLine().getStatusCode();        return statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||statusCode == HttpStatus.SC_MOVED_TEMPORARILY;    }    /**     * function:获得重定向跳转地址     * @param response 请求响应     * @return String 重定向地址     */    private static String   getRedirectedUrl(CloseableHttpResponse response){        String result = EMPTY_STR;        Header[] hs = response.getHeaders("Location");          if(hs.length>0){            result = hs[0].getValue();        }        return result;    }    /**     * function:获得响应实体信息     * @param   response 请求响应     * @return  String 消息实体信息     * @throws  ParseException     * @throws  IOException     */    private static String  getEntityData(CloseableHttpResponse response) throws ParseException, IOException  {        String result = EMPTY_STR;        HttpEntity entity = response.getEntity();        if (entity != null) {                result = EntityUtils.toString(entity);                response.close();        }        return result;    }}
原创粉丝点击