一次http接口调试问题

在开发工程中,我们经常会遇到和其它第三方厂家有接口数据来往的情况。这是一次我们作为客户端
去获取另一个厂家推流的直播地址的接口,这个接口情况有些不一样,我们需要在一个接口中封装两次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;
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值