使用Java進行服務調用時,避免不了要使用模擬HTTP請求來實現模擬,我在開發過程中恰巧遇到了這類的業務需求,所以就對這類的方法進行了一次總結,原理層次的東西暫時不考慮,畢竟HTTP的底層實現啥的,東西挺多且挺復雜的,對我的項目而言,理解這些東西並不能從直觀上得到很明顯的提升或幫助,還是代碼來的比較實在,so,貼出幾種方法的總結,用作備份,免的日后再重復造輪子。
第一種:白痴方案,最原始的解決方案,功能暫時是實現了,但是里面會涉及到通用性和性能等的問題,暫時不考慮,代碼如下
public class HttpRequest { private static final Logger LOGGER = LoggerFactory.getLogger(HttpRequest.class.getName()); /** * 向指定URL發送GET方法的請求 * * @param url 發送請求的URL * @param param 請求參數,請求參數應該是 name1=value1&name2=value2 的形式。 * @return URL 所代表遠程資源的響應結果 */ public static String sendGet(String url, String param) { StringBuilder result = new StringBuilder(); BufferedReader bufferedReader = null; try { String urlNameString = url + "?" + param; URL realUrl = new URL(urlNameString); // 打開和URL之間的連接 URLConnection connection = realUrl.openConnection(); // 設置通用的請求屬性 connection.setRequestProperty("accept", "*/*"); connection.setRequestProperty("connection", "Keep-Alive"); connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); // 建立實際的連接 connection.connect(); // 獲取所有響應頭字段 Map<String, List<String>> map = connection.getHeaderFields(); // 遍歷所有的響應頭字段 for (String key : map.keySet()) { LOGGER.info("key : {}", map.get(key)); System.out.println(key + "--->" + map.get(key)); } // 定義 BufferedReader輸入流來讀取URL的響應 bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line; while ((line = bufferedReader.readLine()) != null) { result.append(line); } } catch (Exception e) { LOGGER.error("HTTP GET error : {}", e.getMessage()); } // 使用finally塊來關閉輸入流 finally { try { if (bufferedReader != null) { bufferedReader.close(); } } catch (Exception e2) { e2.printStackTrace(); } } return result.toString(); } /** * 向指定 URL 發送POST方法的請求 * * @param url 發送請求的 URL * @param param 請求參數,請求參數應該是 name1=value1&name2=value2 的形式。 * @return 所代表遠程資源的響應結果 */ public static String sendPost(String url, String param) { LOGGER.info("url : {}", url); LOGGER.info("param : {}", param); PrintWriter out = null; BufferedReader in = null; StringBuilder result = new StringBuilder(); try { URL realUrl = new URL(url); // 打開和URL之間的連接 URLConnection conn = realUrl.openConnection(); // 設置通用的請求屬性 conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); conn.setRequestProperty("accept-language", "en-US,en;q=0.5"); // 發送POST請求,必須設置如下兩行 conn.setDoOutput(true); conn.setDoInput(true); // 獲取URLConnection對象對應的輸出流 out = new PrintWriter(conn.getOutputStream()); // 發送請求參數 out.print(param); // flush輸出流的緩沖 out.flush(); // 定義BufferedReader輸入流來讀取URL的響應 in = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line; while ((line = in.readLine()) != null) { result.append(line); } } catch (Exception e) { LOGGER.error("HTTP POST error : {}", e.getMessage()); } //使用finally塊來關閉輸出流、輸入流 finally { try { if (out != null) out.close(); if (in != null) in.close(); } catch (IOException ex) { LOGGER.error("close IO error : {}", ex.getMessage()); } } return result.toString(); } }
第二種:升級版本,基於上個版本進行的簡化版,看起來更簡潔一些,代碼如下
public class HttpClientUtil { private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientUtil.class.getName()); public static String sendGet(String url, String param) throws IOException { LOGGER.info("request url info : {}", url); HttpGet request = new HttpGet(url + "?" + param); return send(request); } public static String sendPost(String url, String param) throws IOException { LOGGER.info("request url info : {}", url); HttpPost request = new HttpPost(url); request.setEntity( new StringEntity(param, ContentType.create("application/json;charset=UTF-8")) ); return send(request); } private static String send(HttpRequestBase request) throws IOException { String message = ""; request.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) ..."); request.setHeader("accept", "*/*"); request.setHeader("connection", "Keep-Alive"); CloseableHttpClient httpclient = HttpClients.createDefault(); CloseableHttpResponse response = httpclient.execute(request); HttpEntity entity = response.getEntity(); ByteArrayOutputStream outStream = new ByteArrayOutputStream(); if (entity != null) { long length = entity.getContentLength(); if (length != -1 && length < 2048) { message = EntityUtils.toString(entity); } else { InputStream in = entity.getContent(); byte[] data = new byte[4096]; int count; while ((count = in.read(data, 0, 4096)) != -1) { outStream.write(data, 0, count); } message = new String(outStream.toByteArray(), "UTF-8"); } } LOGGER.info(">>>>>>>>>>>>>>>>>response message info : {}", message); return message; } }
第三種:這一種方案,徹底告別了傻瓜式的輪子創造過程,直接使用開源的,已封裝好的代碼工具來實現這一過程,但是有個問題就是,他會產生輪詢日志,以此保持鏈接通訊,如果看着不爽,可以改源碼里的配置,或者使用log4j2中的日志過濾器,直接將他的日志過濾掉,並只打印程序的日志信息,看起來更清爽一些,代碼如下(PS:這個工具包全方位支持RESFUL請求方式,這里只列舉常用的兩種,其他的請自行實驗)
public class UnirestUtil { private static final Logger LOGGER = LoggerFactory.getLogger(UnirestUtil.class.getName()); /** * * @param url 目標url * @param name 參數名稱 * @param param 請求參數 * @return 網絡傳輸狀態碼或請求結果 */ public static HttpResponse sendGet(String url, String name, String param) throws UnirestException { LOGGER.debug("request url info : {}", url); HttpResponse<String> response = Unirest.get(url) .header("accept", "application/json;charset=UTF-8") .queryString(name, param) .asString(); LOGGER.debug("response status info : {}", response.getStatus()); LOGGER.debug("response status message info : {}", response.getStatusText()); return response; } /** * * @param url 目標url * @param name 參數名稱 * @param param 請求參數實體 * @return 網絡傳輸狀態碼 */ public static HttpResponse sendPost(String url, String name, String param) throws UnirestException { LOGGER.debug("request url info : {}", url); HttpResponse<String> response = Unirest.post(url) .header("accept", "application/json;charset=UTF-8") .queryString(name, param) .asString(); LOGGER.debug("response status info : {}", response.getStatus()); LOGGER.debug("response status message info : {}", response.getStatusText()); return response; } }
OK,至此,幾種方案都貼出來了,可能還有更簡潔可靠的方案來實現這個功能,但是我還沒找到,如果您有更好的方法,請留言交流,分享出來吧,謝謝。
