使用Java內建類HttpUrlConnection實現HTTP請求
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.bkjia.com");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
4. 添加請求參數
如果我們想要添加請求參數,我們需要設定doOutput 為true,然後將請求參數拼接成字串,格式param1=value¶m2=value,以流的形式寫入到HttpUrlConnection 執行個體的OutputStream中。範例程式碼如下:
Map<String, String> parameters = new HashMap<>();
parameters.put("param1", "val");
con.setDoOutput(true);
DataOutputStream out = new DataOutputStream(con.getOutputStream());
out.writeBytes(ParameterStringBuilder.getParamsString(parameters));
out.flush();
out.close();
為方便轉換字串參數,我寫了個工具類ParameterStringBuilder。類中包含一個靜態方法getParamsString()將Map轉換成對應格式的字串:
public class ParameterStringBuilder {
public static String getParamsString(Map<String, String> params)
throws UnsupportedEncodingException{
StringBuilder result = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {
result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
result.append("=");
result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
result.append("&");
}
String resultString = result.toString();
return resultString.length() > 0
? resultString.substring(0, resultString.length() - 1)
: resultString;
}
}
5. 添加要求標頭
通過setRequestProperty() 方法可以添加要求標頭:
con.setRequestProperty("Content-Type", "application/json");
通過getHeaderField()方法可以讀取回應標頭:
String contentType = con.getHeaderField("Content-Type");
6. 配置逾時時間
類允許我們設定連線逾時時間和讀取逾時時間。這些值決定了串連建立的最大等待時間間隔或讀取到達資料的最大等待時間間隔。
設定逾時時間,我們可以調用方法setConnectTimeout() 和方法setReadTimeout():
con.setConnectTimeout(5000);
con.setReadTimeout(5000);
這個例子中我們將逾時時間設為5秒。
7. 處理Cookies
java.net 包包含的類CookieManager,HttpCookie等能很便捷地處理Cookies.
首先,從響應中讀取cookies,我們先擷取相應頭裡的Set-Cookie值,然後解析成HttpCookie對象的List.
String cookiesHeader = con.getHeaderField("Set-Cookie");
List<HttpCookie> cookies = HttpCookie.parse(cookiesHeader);
接下來,我們將cookies儲存起來:
cookies.forEach(cookie -> cookieManager.getCookieStore().add(null, cookie));
我們檢查cookies中是否包含一個username屬性,如果不包含,我們把一個叫zhangsan的username添加進去:
Optional<HttpCookie> usernameCookie = cookies.stream()
.findAny().filter(cookie -> cookie.getName().equals("username"));
if (usernameCookie == null) {
cookieManager.getCookieStore().add(null, new HttpCookie("username", "john"));
}
最後,將cookies添加到請求中去,我們需要在關閉串連和重新開啟串連後,添加Cookie要求標頭 :
con.disconnect();
con = (HttpURLConnection) url.openConnection();
con.setRequestProperty("Cookie",
StringUtils.join(cookieManager.getCookieStore().getCookies(), ";"));
8. 處理重新導向
我們可以通過調用方法setInstanceFollowRedirects(),設定為true或者false,來控制是否允許一個特定串連自動跟隨重新導向:
con.setInstanceFollowRedirects(false);
也可以全域設定所有的串連是否允許自動跟隨重新導向:
HttpUrlConnection.setFollowRedirects(false);
預設是允許自動跟隨重新導向的。
請求返回狀態代碼301,302表示重新導向,我們可以擷取回應標頭的Location屬性並用新的URL建立一個新的串連。
if (status == HttpURLConnection.HTTP_MOVED_TEMP
|| status == HttpURLConnection.HTTP_MOVED_PERM) {
String location = con.getHeaderField("Location");
URL newUrl = new URL(location);
con = (HttpURLConnection) newUrl.openConnection();
}
9. 讀取響應
通過讀取HttpUrlConnection執行個體的InputStream流來讀取響應。
讀取響應常用方法有getResponseCode(), connect(), getInputStream() or getOutputStream() 。
比如,讀取響應狀態代碼:
int status = con.getResponseCode();
比如,讀取回應標頭:
String contentType = con.getHeaderField("Content-Type");
比如,讀取響應文本:
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer content = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
in.close();
關閉串連:
con.disconnect();
結論
在這篇文章中,我們展示了如何通過HttpUrlConnection類來時間Http請求。以下代碼可以直接拷貝使用。由於太簡單,就不傳github了。
package com.bkjia.utils;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
public class HttpUtil {
private static String POST = "POST";
private static String GET = "GET";
private static String CONTENT_TYPE_URLENCODED = "application/x-www-form-urlencoded";
private static String CONTENT_TYPE_JSON = "application/json";
private static String httpRequest(String method, String contentType, String urlStr, HashMap<String,String> paras)
throws IOException {
URL url = new URL(urlStr);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(5000);
con.setReadTimeout(5000);
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
if(paras != null && !paras.isEmpty()){
con.setDoOutput(true);
DataOutputStream out = new DataOutputStream(con.getOutputStream());
out.writeBytes(ParameterStringBuilder.getParamsString(paras));
out.flush();
out.close();
}
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer content = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
in.close();
con.disconnect();
return content.toString();
}
private static class ParameterStringBuilder {
public static String getParamsString(Map<String, String> params)
throws UnsupportedEncodingException {
StringBuilder result = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {
result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
result.append("=");
result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
result.append("&");
}
String resultString = result.toString();
return resultString.length() > 0
? resultString.substring(0, resultString.length() - 1)
: resultString;
}
}
public static String httpGetRequest(String url){
try {
return httpRequest(GET, CONTENT_TYPE_URLENCODED, url, null);
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
public static String httpPostRequest(String url, HashMap<String,String> paras){
try {
return httpRequest(POST, CONTENT_TYPE_URLENCODED, url, paras);
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
}
本文永久更新連結地址:https://www.bkjia.com/Linux/2018-03/151204.htm