1. 概述
在這篇快速教程中,我們將使用Java內置類HttpUrlConnection來實現一個Http請求。
2. HttpUrlConnection
HttpUrlConnection類允許我們不用添加其他任何類庫就能實現基本的Http請求。所有需要的類都包含在 java.net包內。缺點是,相比於其他http類庫,該方法有點笨重,而且也沒有提供一些高級特性的API,比如添加請求頭,添加認證等。不過這些都不要緊。你完全可以將這個實現封裝一下,添加一些高級特性也不是很復雜。
如果你只是想快速地進行些Http請求而不想添加一些類庫的話,本文的這些代碼就足夠了。
另外,如果你對java的http請求基本實現不很了解,本文給出的代碼也會有些幫助。
3. 創建請求
HttpUrlConnection類的創建是通過URL 類的openConnection()方法。這個方法只是創建一個連接對象,並不建立連接。
通過設置requestMethod屬性,HttpUrlConnection類可以創建各種請求類型——包括GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE。
比如創建一個GET請求:
URL url = new URL("www.baidu.com"); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("GET");
4. 添加請求參數
如果我們想要添加請求參數,我們需要設置doOutput 為true,然后將請求參數拼接成字符串,格式param1=value¶m2=value,以流的形式寫入到HttpUrlConnection 實例的OutputStream中。示例代碼如下:
1 Map<String, String> parameters = new HashMap<>(); 2 parameters.put("param1", "val"); 3 4 con.setDoOutput(true); 5 DataOutputStream out = new DataOutputStream(con.getOutputStream()); 6 out.writeBytes(ParameterStringBuilder.getParamsString(parameters)); 7 out.flush(); 8 out.close();
為方便轉換字符串參數,我寫了個工具類ParameterStringBuilder。類中包含一個靜態方法getParamsString()將Map轉換成對應格式的字符串:
1 public class ParameterStringBuilder { 2 public static String getParamsString(Map<String, String> params) 3 throws UnsupportedEncodingException{ 4 StringBuilder result = new StringBuilder(); 5 6 for (Map.Entry<String, String> entry : params.entrySet()) { 7 result.append(URLEncoder.encode(entry.getKey(), "UTF-8")); 8 result.append("="); 9 result.append(URLEncoder.encode(entry.getValue(), "UTF-8")); 10 result.append("&"); 11 } 12 13 String resultString = result.toString(); 14 return resultString.length() > 0 15 ? resultString.substring(0, resultString.length() - 1) 16 : resultString; 17 } 18 }
5. 添加請求頭
通過setRequestProperty() 方法可以添加請求頭:
1 con.setRequestProperty("Content-Type", "application/json");
通過getHeaderField()方法可以讀取響應頭:
1 String contentType = con.getHeaderField("Content-Type");
6. 配置超時時間
類允許我們設置連接超時時間和讀取超時時間。這些值決定了連接建立的最大等待時間間隔或讀取到達數據的最大等待時間間隔。
設置超時時間,我們可以調用方法setConnectTimeout() 和方法setReadTimeout():
1 con.setConnectTimeout(5000); 2 con.setReadTimeout(5000);
這個例子中我們將超時時間設為5秒。
7. 處理Cookies
java.net 包包含的類CookieManager,HttpCookie等能很便捷地處理Cookies.
首先,從響應中讀取cookies,我們先獲取相應頭里的Set-Cookie值,然后解析成HttpCookie對象的List.
1 String cookiesHeader = con.getHeaderField("Set-Cookie"); 2 List<HttpCookie> cookies = HttpCookie.parse(cookiesHeader);
接下來,我們將cookies存儲起來:
1 cookies.forEach(cookie -> cookieManager.getCookieStore().add(null, cookie));
我們檢查cookies中是否包含一個username屬性,如果不包含,我們把一個叫zhangsan的username添加進去:
1 Optional<HttpCookie> usernameCookie = cookies.stream() 2 .findAny().filter(cookie -> cookie.getName().equals("username")); 3 if (usernameCookie == null) { 4 cookieManager.getCookieStore().add(null, new HttpCookie("username", "john")); 5 }
最后,將cookies添加到請求中去,我們需要在關閉連接和重新打開連接后,添加Cookie請求頭 :
1 con.disconnect(); 2 con = (HttpURLConnection) url.openConnection(); 3 4 con.setRequestProperty("Cookie", 5 StringUtils.join(cookieManager.getCookieStore().getCookies(), ";"));
8. 處理重定向
我們可以通過調用方法setInstanceFollowRedirects(),設置為true或者false,來控制是否允許一個特定連接自動跟隨重定向:
1 con.setInstanceFollowRedirects(false);
也可以全局設置所有的連接是否允許自動跟隨重定向:
1 HttpUrlConnection.setFollowRedirects(false);
默認是允許自動跟隨重定向的。
請求返回狀態碼301,302表示重定向,我們可以獲取響應頭的Location屬性並用新的URL創建一個新的連接。
1 if (status == HttpURLConnection.HTTP_MOVED_TEMP 2 || status == HttpURLConnection.HTTP_MOVED_PERM) { 3 String location = con.getHeaderField("Location"); 4 URL newUrl = new URL(location); 5 con = (HttpURLConnection) newUrl.openConnection(); 6 }
9. 讀取響應
通過讀取HttpUrlConnection實例的InputStream流來讀取響應。
讀取響應常用方法有getResponseCode(), connect(), getInputStream() or getOutputStream() 。
比如,讀取響應狀態碼:
1 int status = con.getResponseCode();
比如,讀取響應頭:
1 String contentType = con.getHeaderField("Content-Type");
比如,讀取響應文本:
1 BufferedReader in = new BufferedReader( 2 new InputStreamReader(con.getInputStream())); 3 String inputLine; 4 StringBuffer content = new StringBuffer(); 5 while ((inputLine = in.readLine()) != null) { 6 content.append(inputLine); 7 } 8 in.close();
關閉連接:
1 con.disconnect();
結論
在這篇文章中,我們展示了如何通過HttpUrlConnection類來時間Http請求。以下代碼可以直接拷貝使用。由於太簡單,就不傳github了。

1 package com.shlugood.utils; 2 3 import java.io.*; 4 import java.net.HttpURLConnection; 5 import java.net.URL; 6 import java.net.URLEncoder; 7 import java.util.HashMap; 8 import java.util.Map; 9 10 public class HttpUtil { 11 12 private static String POST = "POST"; 13 private static String GET = "GET"; 14 private static String CONTENT_TYPE_URLENCODED = "application/x-www-form-urlencoded"; 15 private static String CONTENT_TYPE_JSON = "application/json"; 16 17 private static String httpRequest(String method, String contentType, String urlStr, HashMap<String,String> paras) 18 throws IOException { 19 URL url = new URL(urlStr); 20 HttpURLConnection con = (HttpURLConnection) url.openConnection(); 21 con.setConnectTimeout(5000); 22 con.setReadTimeout(5000); 23 con.setRequestMethod("POST"); 24 con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 25 26 if(paras != null && !paras.isEmpty()){ 27 con.setDoOutput(true); 28 DataOutputStream out = new DataOutputStream(con.getOutputStream()); 29 out.writeBytes(ParameterStringBuilder.getParamsString(paras)); 30 out.flush(); 31 out.close(); 32 } 33 34 35 BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); 36 String inputLine; 37 StringBuffer content = new StringBuffer(); 38 while ((inputLine = in.readLine()) != null) { 39 content.append(inputLine); 40 } 41 in.close(); 42 con.disconnect(); 43 return content.toString(); 44 } 45 46 private static class ParameterStringBuilder { 47 public static String getParamsString(Map<String, String> params) 48 throws UnsupportedEncodingException { 49 StringBuilder result = new StringBuilder(); 50 51 for (Map.Entry<String, String> entry : params.entrySet()) { 52 result.append(URLEncoder.encode(entry.getKey(), "UTF-8")); 53 result.append("="); 54 result.append(URLEncoder.encode(entry.getValue(), "UTF-8")); 55 result.append("&"); 56 } 57 58 String resultString = result.toString(); 59 return resultString.length() > 0 60 ? resultString.substring(0, resultString.length() - 1) 61 : resultString; 62 } 63 } 64 65 66 public static String httpGetRequest(String url){ 67 try { 68 return httpRequest(GET, CONTENT_TYPE_URLENCODED, url, null); 69 } catch (IOException e) { 70 e.printStackTrace(); 71 } 72 return ""; 73 } 74 75 public static String httpPostRequest(String url, HashMap<String,String> paras){ 76 try { 77 return httpRequest(POST, CONTENT_TYPE_URLENCODED, url, paras); 78 } catch (IOException e) { 79 e.printStackTrace(); 80 } 81 return ""; 82 } 83 }