简单封装 HTTP 请求
2017-2-19 更新到第二版:
源碼地址:http://git.oschina.net/sp42/ajaxjs/tree/master/ajaxjs-base/src/com/ajaxjs/net?dir=1&filepath=ajaxjs-base%2Fsrc%2Fcom%2Fajaxjs%2Fnet
和文件操作一樣,其內部使用了鏈式風格的調用方式。
GET/HEAD 請求
GET 請求用法參見下面的測試用例,包括普通 GET 請求、獲取 302 重定向調轉地址、獲取資源文件體積大小、是否 404以及下載二進制文件等功能。
String url = "http://localhost:8080/pachong/post.jsp"; String result = Client.POST(url, new HashMap<String, Object>() {private static final long serialVersionUID = 1L;{put("foo", "bar");} }); System.out.println("Feedback:" + result);
2016-7-12 : 新增 GZip 請求和 Gzip 響應判斷。
請求判斷
if(request.isEnableGzip()) // 是否啟動 GZip 請求connection.addRequestProperty("Accept-Encoding", "gzip, deflate");一般情況下,請求頭加入了上面的 Accept-Encoding 字段,服務器才會對內容進行 GZip 壓縮,否則就不壓縮,原文輸出。但有些網站是不管有沒有這種請求都一概返回 GZIP 的。如果有 GZIP,服務器會告訴我們的,在響應頭中加入 Content-Encoding 的字段。響應判斷:
// 是否啟動 GZip 請求// 有些網站強制加入 Content-Encoding:gzip,而不管之前的是否有 GZip 的請求boolean isGzip = request.isEnableGzip() || "gzip".equals(connection.getHeaderField("Content-Encoding"));如果不對 Gzip 的內容進行 GZipInputStream 處理會一段亂碼。
測試用例:
@Testpublic void testGZipGet() {Request request = new Request();request.setUrl("http://u.3gtv.net");request.setEnableGzip(true);RequestClient rc = new RequestClient(request);try {rc.connect();} catch (ConnectException e) {System.out.println("請求出錯" + request.getUrl());}String html = request.getFeedback();System.out.println(html);assertNotNull(html);}// B 站強制 Gzip 返回,無論請求是否帶有 GZIP@Testpublic void testForce_GZipGet() {String url = "http://www.bilibili.com/video/av5178498/";String html = Get.GET(url);System.out.println(html);assertNotNull(html);}-------------------------------------------------------------------------------------------------------------
簡單封裝 Java 類庫里面的 HttpURLConnection 來完成日常的 HTTP 請求,如 GET、HEAD、POST 等的請求。
GET 請求用法參見下面的測試用例,包括普通 GET 請求、獲取 302 重定向調轉地址、獲取資源文件體積大小、是否 404以及下載二進制文件等功能。
Get.simpleGET 和 Get.GET 用法一致,傳入 url 參數,返回該網址的文本內容。具體不同可能要看看源碼。simpleGET 是原始 API 版, 一句話完事的:new URL(url).openStream(),然后把字符流轉為 text 即可。Get.GET 也是字符流轉為 text,只是前期處理上不是調 API,為自己實現邏輯,遵循了 bean 方式的調用。這種方式在咱們這個 HTTP 庫里面的是通用方式。首先 Request 類是一個 Java bean,定義了請求地址 HTTP Url、請求方法 HTTP Mehtod,還有若干常見的 HTTP 頭,都做成了 getter/setter,使用者按照 Request 類的方法調用即可。其次 GET 請求和 POST 請求本身就差別不少,因此劃分為 Get/Post 兩個類。但實際發出請求的是 RequestClient 類。這個類是不管哪種請求的,都是圍繞后期 HTTP 響應作處理,主要是流的處理,以及一些諸如 404、超時異常的處理。下面是 RequestClient 源碼:
import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.SocketTimeoutException; import java.net.URL; import java.net.UnknownHostException;import com.ajaxjs.util.FileUtil; import com.ajaxjs.util.StringUtil;import sun.misc.BASE64Encoder;/*** 發起 HTTP 請求* @author frank**/ public class RequestClient {/*** 請求目標地址*/private URL url;/*** API 鏈接對象*/private HttpURLConnection connection;/*** 攜帶請求信息的 Bean*/private Request request;/*** 創建 HTTP 請求* * @param request* 請求信息對象*/public RequestClient(Request request) {this.request = request;try {url = new URL(request.getUrl());connection = (HttpURLConnection) url.openConnection();connection.setRequestMethod(request.getMethod());} catch (IOException e) {System.err.println("初始化連接出錯!" + request.getUrl());e.printStackTrace();}}/*** 內部初始化*/private void init() {connection.addRequestProperty("User-Agent", request.getUserAgent());connection.addRequestProperty("Referer", request.getUrl() == null ? url.getHost() : request.getUrl());connection.setConnectTimeout(request.getTimeout() * 1000);// 設置超時// connection.setReadTimeout(30000);if (request.getCookies() != null) {String cookieStr = StringUtil.HashJoin(request.getCookies(), ";");connection.setRequestProperty("Cookie", cookieStr);}if (request.getBasicAuthorization() != null) { // HTTP 用戶認證String username = request.getBasicAuthorization()[0], password = request.getBasicAuthorization()[1];String encoding = new BASE64Encoder().encode((username + ":" + password).getBytes());connection.setRequestProperty("Authorization", "Basic " + encoding);}}/*** 發起請求* * @return true 表示為發起請求成功* @throws ConnectException*/public boolean connect() throws ConnectException {init();// 寫入數據(POST ONLY, GET 不需要)if (request.getWriteData() != null && !request.getMethod().equalsIgnoreCase("GET")) {// 寫入 POST 數據try (OutputStream os = connection.getOutputStream()) {os.write(request.getWriteData());os.flush();} catch (IOException e) {e.printStackTrace();return false;}}// 接受響應try (InputStream is = connection.getInputStream();) {if (connection.getResponseCode() >= 400) {// 如果返回的結果是400以上,那么就說明出問題了ConnectException e = null;if (connection.getResponseCode() < 500) {e = new ConnectException(connection.getResponseCode() + ":客戶端請求參數錯誤!");} else {e = new ConnectException(connection.getResponseCode() + ":抱歉!我們服務端出錯了!");}String msg = FileUtil.readText(is);e.setFeedback(msg);if (request.isTextResponse())request.setFeedback(msg);throw e;}if (request.getCallback() != null) {request.getCallback().onDataLoad(is);}if (request.isTextResponse())request.setFeedback(FileUtil.readText(is));} catch (UnknownHostException e) {throw new ConnectException("未知地址!" + request.getUrl());} catch (FileNotFoundException e) {throw new ConnectException("404 地址!" + request.getUrl());} catch (SocketTimeoutException e) {throw new ConnectException("請求地址超時!" + request.getUrl());} catch (IOException e) {try {System.out.println(connection.getResponseCode());} catch (IOException e1) {e1.printStackTrace();}throw new ConnectException("請求地址 IO 異常!" + request.getUrl());}return true;} public URL getUrl() {return url;}public void setUrl(URL url) {this.url = url;}public Request getRequest() {return request;}public void setRequest(Request request) {this.request = request;}public HttpURLConnection getConnection() {return connection;}public void setConnection(HttpURLConnection connection) {this.connection = connection;}}其他源碼就不張貼了,有興趣的可以到這里看全部源碼。
POST 例子不多,先放一個:
String url = "http://localhost:8080/pachong/post.jsp"; Request request = Post.POST(url, new HashMap<String, Object>() {private static final long serialVersionUID = 1L;{put("foo", "bar");} }); System.out.println("Feedback:" + request.getFeedback()); assertNotNull(request); assertTrue(request.isDone());代碼比較簡單,應該沒有什么晦澀的地方。請大家多給給意見。
總結
以上是生活随笔為你收集整理的简单封装 HTTP 请求的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 『创建型』简单工厂SimpleFacto
- 下一篇: 使用tomcat自带的连接池,报错