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以及下载二进制文件等功能。
System.out.println(Client.GET("https://www.baidu.com/")); // 获取资源文件体积大小 long size = Client.getFileSize("http://c.csdnimg.cn/jifen/images/xunzhang/xunzhang/bokezhuanjiamiddle.png"); assertEquals(size, 4102L); // 获取 302 重定向跳转地址 System.out.println(Client.get302redirect("https://baidu.com")); // 封装 head 请求检测是否 404 assertTrue(!Client.is404("http://c.csdnimg.cn/jifen/images/xunzhang/xunzhang/bokezhuanjiamiddle.png")); // B 站强制 Gzip 返回,無論请求是否带有 GZIP 字段 System.out.println(Client.GET_Gzip("http://www.bilibili.com/video/av5178498/"));POST 请求
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 处理会一段乱码。
测试用例:
@Test public 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 @Test public 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以及下载二进制文件等功能。
import static org.junit.Assert.*; import org.junit.Test; import java.io.IOException; import com.ajaxjs.net.http.Get; import com.ajaxjs.util.FileUtil; public class TestGet { @Test public void testSimpleGET() { String url = "https://baidu.com"; String html = Get.simpleGET(url); System.out.println(html); assertNotNull(html); } @Test public void testGet() { String url = "https://baidu.com"; String html = Get.GET(url); System.out.println(html); assertNotNull(html); } @Test public void testGet302redirect() { String url = "http://baidu.com"; String location = Get.get302redirect(url); System.out.println(location); assertNotNull(location); } @Test public void testIs404() { String url = "http://c.csdnimg.cn/jifen/images/xunzhang/xunzhang/bokezhuanjiamiddle.png"; assertTrue(!Get.is404(url)); assertTrue(Get.is404("http://www.qq.com/54543")); } @Test public void testGetFileSize() { String url = "http://c.csdnimg.cn/jifen/images/xunzhang/xunzhang/bokezhuanjiamiddle.png"; long size = Get.getFileSize(url); assertEquals(size, 4102L); } @Test public void testDownload2disk() throws IOException { String url = "http://c.csdnimg.cn/jifen/images/xunzhang/xunzhang/bokezhuanjiamiddle.png"; Get.download2disk(url, "c:/temp/dd.png"); String saveTo = "c:/temp/js.js"; Get.download2disk("http://bdimg.share.baidu.com/static/api/js/base/tangram.js?v=37768233.js", saveTo); assertNotNull(FileUtil.readFileAsText(saveTo)); } }
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());
代码比较简单,应该没有什么晦涩的地方。请大家多给给意见。