您的位置:首页 > 理论基础 > 计算机网络

HttpURLConnection对象的获取

2017-09-20 20:21 337 查看

1,获取HttpURLConnection对象

获取HttpURLConnection对象有不同的方法.

以下分析都是基于android 6.0

1,通过URL对象获取,

getUrl = new URL("http://•••/");
mSocketAddress = new InetSocketAddress(•••,mProxyPort);
Proxy proxy = new Proxy(Proxy.Type.HTTP,mSocketAddress);
conn = (HttpURLConnection) getUrl.openConnection(proxy);


2,通过Network对象获取,

getUrl = new URL("http://•••/");
mSocketAddress = new InetSocketAddress(•••,mProxyPort);
Proxy proxy = new Proxy(Proxy.Type.HTTP,mSocketAddress);
conn = (HttpURLConnection) mNetwork.openConnection(getUrl,proxy);

1.1通过URL对象获取

1.1.1 URL对象构造

URL有6个构造方法,仅有一个String参数的构造方法如下,

public URL(String spec) throws MalformedURLException {
this((URL) null, spec, null);
}

三个参数的URL构造方法主要逻辑如下,

1,调用setupStreamHandler方法获取URLStreamHandler对象,

if (streamHandler == null) {
setupStreamHandler();
if (streamHandler == null) {
throw new MalformedURLException("Unknown protocol: " + protocol);
}
}

2,调用URLStreamHandler对象的parseURL方法解析网址,

try {
streamHandler.parseURL(this, spec, schemeSpecificPartStart, spec.length());
} catch (Exception e) {
throw new MalformedURLException(e.toString());
}

setupStreamHandler的主要逻辑如下,

1,如果streamHandlers Hashtable里面已经保存了就直接从里面取出来就可以了,

streamHandler = streamHandlers.get(protocol);
if (streamHandler != null) {
return;
}

一般一个网址对应一个URLStreamHandler对象。

2,如果URLStreamHandlerFactory对象不为空就可以利用URLStreamHandlerFactory创建URLStreamHandler对象,

if (streamHandlerFactory != null) {
streamHandler = streamHandlerFactory.createURLStreamHandler(protocol);
if (streamHandler != null) {
streamHandlers.put(protocol, streamHandler);
return;
}
}

当然,可以并且只能通过setURLStreamHandlerFactory方法设置URLStreamHandlerFactory对象。

3,如果系统内已经有可以加载URLStreamHandler的包,就优先使用系统的包加载,

String packageList = System.getProperty("java.protocol.handler.pkgs");
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
if (packageList != null && contextClassLoader != null) {
for (String packageName : packageList.split("\\|")) {
String className = packageName + "." + protocol + ".Handler";
try {
Class<?> c = contextClassLoader.loadClass(className);
streamHandler = (URLStreamHandler) c.newInstance();
if (streamHandler != null) {
streamHandlers.put(protocol, streamHandler);
}
return;
} catch (IllegalAccessException ignored) {
} catch (InstantiationException ignored) {
} catch (ClassNotFoundException ignored) {
}
}
}

4,最后根据网址的类型分别构造对应的URLStreamHandler对象.

if (protocol.equals("file")) {
streamHandler = new FileHandler();
} else if (protocol.equals("ftp")) {
streamHandler = new FtpHandler();
} else if (protocol.equals("http")) {
try {
String name = "com.android.okhttp.HttpHandler";
streamHandler = (URLStreamHandler) Class.forName(name).newInstance();
} catch (Exception e) {
throw new AssertionError(e);
}
} else if (protocol.equals("https")) {
try {
String name = "com.android.okhttp.HttpsHandler";
streamHandler = (URLStreamHandler) Class.forName(name).newInstance();
} catch (Exception e) {
throw new AssertionError(e);
}
•••

URLStreamHandler其实是一个抽象类,具体的由各个子类实现。在此,根据不同的请求获取不同的URLStreamHandler子类。

http格式的网址对应的是HttpHandler类。

1.1.2 HttpURLConnection对象

通过URL对象获取HttpURLConnection对象的openConnection方法也有2个,其实就是有没有指定代理(特定APN)的区别,

有代理的openConnection调用流程图如下,



URL的openConnection方法如下,

public URLConnection openConnection(Proxy proxy) throws IOException {
if (proxy == null) {
throw new IllegalArgumentException("proxy == null");
}
return streamHandler.openConnection(this, proxy);
}

streamHandler就是在上个小节中获取的URLStreamHandler对象,

对于http格式的网址,对应的是URLStreamHandler的子类HttpHandler。

HttpHandler的openConnection方法如下,

protected URLConnection openConnection(URL url, Proxy proxy) throws IOException {
if (url == null || proxy == null) {
throw new IllegalArgumentException("url == null || proxy == null");
}
return newOkUrlFactory(proxy).open(url);
}

该方法首先调用newOkUrlFactory方法构造OkUrlFactory对象,然后调用其open方法。newOkUrlFactory方法逻辑如下,

protected OkUrlFactory newOkUrlFactory(Proxy proxy) {
OkUrlFactory okUrlFactory = createHttpOkUrlFactory(proxy);
•••
okUrlFactory.client().setConnectionPool(configAwareConnectionPool.get());
return okUrlFactory;
}

createHttpOkUrlFactory方法主要逻辑如下,

1,构造OkHttpClient对象,

OkHttpClient client = new OkHttpClient();

2,利用OkHttpClient对象设置代理,

if (proxy != null) {
client.setProxy(proxy);
}

3,利用OkHttpClient对象构造OkUrlFactory对象,

OkUrlFactory okUrlFactory = new OkUrlFactory(client);

OkUrlFactory的open方法如下,

public HttpURLConnection open(URL url) {
return open(url, client.getProxy());
}

Open方法也会根据网址构造不同的HttpURLConnection代理对象,

HttpURLConnection open(URL url, Proxy proxy) {
String protocol = url.getProtocol();
OkHttpClient copy = client.copyWithDefaults();
copy.setProxy(proxy);

if (protocol.equals("http")) return new HttpURLConnectionImpl(url, copy);
if (protocol.equals("https")) return new HttpsURLConnectionImpl(url, copy);
throw new IllegalArgumentException("Unexpected protocol: " + protocol);
}

以http请求为例,通过URLConnection的openConnection方法最后获取的HttpURLConnection对象

其实是代理HttpURLConnectionImpl对象。

1.2通过Network对象获取

Network的openConnection方法逻辑如下,

1,利用请求网址调用HttpHandler的createHttpOkUrlFactory方法构造OkUrlFactory对象,

if (protocol.equals("http")) {
okUrlFactory = HttpHandler.createHttpOkUrlFactory(proxy);
} else if (protocol.equals("https")) {
okUrlFactory = HttpsHandler.createHttpsOkUrlFactory(proxy);
}

HttpHandler的createHttpOkUrlFactory方法在上个小节已经论述了,此就不赘述了。

2,调用OkUrlFactory对象的open方法创建HttpURLConnectionImpl对象。

return okUrlFactory.open(url);

由此可见,这2中方法最后都会调用OkUrlFactory对象的open方法创建HttpURLConnectionImpl对象,实质完全相同。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息