概念
URI(Uniform Resource Identifier)
- URI是互联网上标识某一资源的字符串,是一个抽象的概念。
- URI通常由三部分组成:资源的命名机制;存放资源的主机名;资源自身的名称。
URL(uniform resource locator)
- URL是互联网上描述信息资源的字符串,主要用在各种WWW客户程序和服务器程序上,URL是URI概念的一种实现方式,提供了定位资源的具体方式。
- URL的一般格式为(带方括号[]的为可选项):
protocol :// hostname[:port] / path / [;parameters][?query]#fragment - URL的格式由三部分组成:
1.协议(或称为服务方式);
2.存有该资源的主机IP地址(有时也包括端口号);
3.主机资源的具体地址,如目录和文件名等;
其中,第一部分和第二部分用“://”符号隔开,第二部分和第三部分用“/”符号隔开,第一部分和第二部分是不可缺少的,第三部分有时可以省略。
URLConnection
https://docs.oracle.com/javase/7/docs/api/java/net/URLConnection.html
URLConnection抽象类为应用程序提供了访问URL的方式,其示例提供了读写URL资源的方法。
HTTPURLConnection
https://docs.oracle.com/javase/7/docs/api/java/net/HttpURLConnection.html
HTTPURLConnection是提供了对HTTP协议支持的URLConnection。
示例
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
public class GreetingURLConn {
public static void main(String[] args) {
testRead();
}
private static void testRead() {
InputStream input = null;
try {
// 连接
URL url = new URL("http://www.baidu.com");
URLConnection connection = url.openConnection();
// 读取
input = connection.getInputStream();
InputStream raw = new BufferedInputStream(input);
Reader r = new InputStreamReader(raw);
StringBuffer result = new StringBuffer();
int c;
while ((c = r.read()) > 0) {
result.append((char) c);
}
System.out.println(result);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (input != null) {
input.close();
}
} catch (IOException ignore) {
}
}
}
}
源码分析
Url.openConnection
- 调用
URLStreamHandler
的 openConnection, 不同的协议有不同的URLStreamHandler
- 以HTTP协议的Handler为例,openConnection其实就是构建一个HttpURLConnection实例
package sun.net.www.protocol.http;
...
public class Handler extends URLStreamHandler{
...
protected URLConnection openConnection(URL var1, Proxy var2) throws IOException {
return new HttpURLConnection(var1, var2, this);
}
}
HttpURLConnection.getInputStream
private synchronized InputStream getInputStream0() throws IOException {
if (...) { // 异常检查
...
} else if (this.inputStream != null) { // 缓存
return this.inputStream;
} else {
// 如果正在写入,先处理写入
if (this.streaming()) {
if (this.strOutputStream == null) {
this.getOutputStream();
}
this.strOutputStream.close();
if (!this.strOutputStream.writtenOK()) {
throw new IOException("Incomplete output stream");
}
}
...
InputStream var45;
try {
int var33;
while(true) {
if (!this.checkReuseConnection()) {
// 这里会构建HttpClient,存储为成员变量http
// HttpClient有缓存机制
// 构建HttpClient的时候,会创建socket实例,并获得输出通道存道,存储为HttpClient的成员变量serverOutput
this.connect();
}
...
this.ps = (PrintStream)this.http.getOutputStream();
if (!this.streaming()) {
// 构建request,通过HttpClient写入serverOutput,具体见下方
this.writeRequests();
}
// 通过HttpClient获得输入通道,存储为HttpClient的成员变量serverInput,并初步解析到MessageHeader类型的实例responses中
this.http.parseHTTP(this.responses, this.pi, this);
...
this.inputStream = this.http.getInputStream();
// 获取responseCode并做一些异常处理
var33 = this.getResponseCode();
if (var33 == -1) {
this.disconnectInternal();
throw new IOException("Invalid Http response");
}
...
if (var33 == 200) {
this.checkResponseCredentials(false);
} else {
this.needToCheck = false;
}
this.needToCheck = true;
...
}
return var45;
}
}
writeRequests
private void writeRequests() throws IOException {
if (this.http.usingProxy && this.tunnelState() != HttpURLConnection.TunnelState.TUNNELING) {
this.setPreemptiveProxyAuthentication(this.requests);
}
if (!this.setRequests) {
// 各种公共Header处理 ,如 "Content-type"
...
if (!this.method.equals("PUT") && (this.poster != null || this.streaming()))
{
this.requests.setIfNotSet("Content-type", "application/x-www-form-urlencoded");
}
this.setCookieHeader();
this.setRequests = true;
}
// 在HTTPClient中写入请求流
this.http.writeRequests(this.requests, this.poster, this.streaming());
if (this.ps.checkError()) { // IO异常,重新处理一次请求
...
if (this.failedOnce) {
throw new IOException("Error writing to server");
}
this.failedOnce = true;
// 重置一些参数和http实例,略
...
this.writeRequests();
}
}