一次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方法是這樣寫的:java

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 中不會作這個驗證。因此問題找到了,因此咱們把這個方法換成其它方式來構造就正常返回了。apache

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。json

最後附上封裝的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;
    }

}
相關文章
相關標籤/搜索