概念
URI(Uniform Resource Identifier)
- URI是互聯(lián)網(wǎng)上標(biāo)識(shí)某一資源的字符串木蹬,是一個(gè)抽象的概念吹埠。
- URI通常由三部分組成:資源的命名機(jī)制凡怎;存放資源的主機(jī)名协屡;資源自身的名稱实蓬。
URL(uniform resource locator)
- URL是互聯(lián)網(wǎng)上描述信息資源的字符串茸俭,主要用在各種WWW客戶程序和服務(wù)器程序上,URL是URI概念的一種實(shí)現(xiàn)方式安皱,提供了定位資源的具體方式调鬓。
- URL的一般格式為(帶方括號(hào)[]的為可選項(xiàng)):
protocol :// hostname[:port] / path / [;parameters][?query]#fragment - URL的格式由三部分組成:
1.協(xié)議(或稱為服務(wù)方式);
2.存有該資源的主機(jī)IP地址(有時(shí)也包括端口號(hào))酌伊;
3.主機(jī)資源的具體地址腾窝,如目錄和文件名等;
其中居砖,第一部分和第二部分用“://”符號(hào)隔開虹脯,第二部分和第三部分用“/”符號(hào)隔開,第一部分和第二部分是不可缺少的奏候,第三部分有時(shí)可以省略循集。
URLConnection
https://docs.oracle.com/javase/7/docs/api/java/net/URLConnection.html
URLConnection抽象類為應(yīng)用程序提供了訪問URL的方式,其示例提供了讀寫URL資源的方法蔗草。
HTTPURLConnection
https://docs.oracle.com/javase/7/docs/api/java/net/HttpURLConnection.html
HTTPURLConnection是提供了對(duì)HTTP協(xié)議支持的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
- 調(diào)用
URLStreamHandler
的 openConnection, 不同的協(xié)議有不同的URLStreamHandler
- 以HTTP協(xié)議的Handler為例,openConnection其實(shí)就是構(gòu)建一個(gè)HttpURLConnection實(shí)例
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()) {
// 這里會(huì)構(gòu)建HttpClient蔼紧,存儲(chǔ)為成員變量http
// HttpClient有緩存機(jī)制
// 構(gòu)建HttpClient的時(shí)候婆硬,會(huì)創(chuàng)建socket實(shí)例狠轻,并獲得輸出通道存道,存儲(chǔ)為HttpClient的成員變量serverOutput
this.connect();
}
...
this.ps = (PrintStream)this.http.getOutputStream();
if (!this.streaming()) {
// 構(gòu)建request彬犯,通過(guò)HttpClient寫入serverOutput向楼,具體見下方
this.writeRequests();
}
// 通過(guò)HttpClient獲得輸入通道,存儲(chǔ)為HttpClient的成員變量serverInput谐区,并初步解析到MessageHeader類型的實(shí)例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中寫入請(qǐng)求流
this.http.writeRequests(this.requests, this.poster, this.streaming());
if (this.ps.checkError()) { // IO異常,重新處理一次請(qǐng)求
...
if (this.failedOnce) {
throw new IOException("Error writing to server");
}
this.failedOnce = true;
// 重置一些參數(shù)和http實(shí)例宋列,略
...
this.writeRequests();
}
}