HTTP是应用最广泛的应用层协议,JavaSE内置了HttpURLConnection对象,它可以作为一个简单的HTTP客户端,在编写服务调用客户端、爬虫程序、GUI程序和Android应用时都比较常用。HttpURLConnection这个类的方法很多,这里不会逐一介绍,只是记录几个使用HttpURLConnection的最佳实践,以备日后查阅。有关更详细的方法使用,可以参考JDK文档。
public class Main {
public static void main(String[] args) throws Exception {
File file = new File("/home/gacfox/test.html");
FileOutputStream fileOutputStream = new FileOutputStream(file);
//初始化请求URL
URL url = new URL("http://www.baidu.com");
//获取HttpURLConnection对象
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//发起HTTP请求
connection.connect();
//读取响应状态码,200表示OK
if (connection.getResponseCode() == 200) {
//获取响应体输入流
InputStream inputStream = connection.getInputStream();
//读取输入流写入文件
byte[] buffer = new byte[1024];
int n;
while ((n = inputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, n);
}
inputStream.close();
fileOutputStream.close();
}
}
}
这里我们向一个网页发起GET请求,显然响应体是一个HTML页面,我们获得了这个页面内容的输入流,并将其存入一个文件中。
注:为了代码美观,上面我们对HttpURLConnection并没有配置很多属性,因为它的很多属性默认值就是我们需要的。具体请参考文档。
public class Main {
public static void main(String[] args) throws Exception {
URL url = new URL("http://localhost:8080/TestPost/TestServlet");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
//获取请求体输出流
connection.setDoOutput(true);
DataOutput dataOutput = new DataOutputStream(connection.getOutputStream());
//向请求体写入数据
dataOutput.write("param1=a¶m2=b".getBytes(StandardCharsets.UTF_8));
connection.connect();
if (connection.getResponseCode() == 200) {
System.out.println("POST请求成功");
}
}
}
上面代码演示了使用POST方式,向一个URL提交表单数据。实际上HttpURLConnection提供的接口比较底层,并没有区分POST的是表单还是二进制数据,统统使用OutputStream。这里POST的地址是一个Servlet编写的后台,后台可以正常收到POST的参数即:param1 = a
和param2 = b
。
下面例子代码设置了User-Agent
请求头。
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0");
Map<String, List<String>> headerFields = connection.getHeaderFields();
for (String headerKey : headerFields.keySet()) {
System.out.println(headerKey);
for (String headerValue : headerFields.get(headerKey)) {
System.out.println(headerValue);
}
}
我们可以通过connection.getHeaderFields()
拿到所有响应头信息的Map对象,然后读取即可。下面是Tomcat服务器默认的返回结果:
null
HTTP/1.1 200 OK
Server
Apache-Coyote/1.1
Content-Length
0
Date
Tue, 18 Jul 2017 14:11:06 GMT
HttpURLConnection并没有提供和Cookie相关的API,但是这并不影响我们使用Cookie。当请求网页时,我们可以从响应头的Set-Cookie
属性中,读取服务器向我们设置的所有Cookie。我们向服务器发起请求时,则可以在请求头中的Cookie
属性中,带上需要发给服务器的Cookie。
我们可以自己使用Map存储Cookie,也可以使用JavaSE内置的java.net.CookieManager
存储。
在内网中如果用到HTTPS协议通常都会使用自签名证书,而非真实有效的证书,此时如果使用HttpURLConnection客户端访问证书存在错误的HTTPS服务时会报错,不过我们可以通过代码配置忽略HTTPS证书相关的问题。
TrustManager[] trustAllCertificates = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCertificates, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier((hostname, sslSession) -> true);
} catch (NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
当然,这种方式存在一定的安全风险,实际开发中我们应该结合具体需求合理进行设置。