Java网络编程之URL和URI
来源:互联网 发布:铁幕演说知乎 编辑:程序博客网 时间:2024/05/22 13:13
- URL和URI
- URI
- URLs
- 相对URL
- URL类
- 从URL获取数据
- 分解URL
- equals和hashcode
- 转换
- URI类
- 构造
- URI的各部分
- 解析相对URI
- equals
- 字符串表示
- URLEncoder
- URLDEcoder
- 代理
URL和URI
URL可以唯一地标识一个资源在Internet上的位置。URL是最常见的URI
URI
URI是采用一种特定的语法标识一个资源的字符串.例如https://www.myserver.com/a.png
URI的结构:模式:模式特定部分
常见的模式有:
data file ftp http mailto magnet telnet urn
模式特定部分一般采用层次的结构,非ASCII字符要转换成UTF-8编码的十六进制码
URLs
URL是一个URI,除了标识一个资源,还会为资源提供一个特定的网络位置,客户端可以用它来获取这个资源。与之不同的时,通常URI可以告诉你一个资源是什么,但是无法告诉你在哪里,以及如何得到这个资源。
URL中的网络位置通常包括用来访问服务器的协议(FTP、HTTP)、服务器的主机或IP地址、以及文件在该服务器上的路径。
URL的语法为:
protocol://userInfo@host:port/path?query#fragment
这里的protocol就是URI的模式(scheme);userInfo可选;端口也是可选的;用户信息、主机和端口构成一个authority;fragment是片段,指向远程资源的某个特定的部分,比如某个HTML的标签的ID(这样的话,严格上说是URL引用,但是JAVA不做区分)。
相对URL
URL可以继承其父文档的协议、主机名和路径,因此可以使用相对URL,例如:
<a href="javafaq.html">
这个超链接在http://www.gg.com/gg/a.html中,那么这连接的地址是:http://www.gg.com/gg/javafaq.html
如果相对连接是以“/”开头,那么它相对于文档根目录,例如:
<a href="/projects/ipv6">
URL类
java的URL是一个final类,因此是线程安全的,并且使用了策略设计模式
创建URL的方法:
public URL(String url) throws MalformedURLException;public URL(String protocol, String hostname, String file) throws MalformedURLException;public URL(String protocol, String host, int prot, String file) throws MalformedURLEXception;public URL(URL base, String relative) throws MalformedURLException
能否支持某个协议取决于虚拟机,如果不支持可以安装一个协议处理器,当然更好的方法就是使用一个库
除了验证能否识别URL模式外,java不会它构造的URL完成任何正确性检查。程序员要负责确保所创建的URL是合法的。
从组成部分创建URL
public URL(String protocol, String hostname, String file) throws MalformedURLException;
此方法等同于调用带四个参数的构造方法,四个参数为 protocol、host、-1(即采用默认端口) 和 file。 此构造方法不执行对输入的验证。注意file中不要忘了写“/”
其他方式获取URL
java.io.File类有一个toURL()方法,可以产生一个和平台有关的URL
ClassLoader.getSystemResource(String name)可以返回一个URL
ClassLoader.getSystemRecources(String name)返回包含URL的Enumeration
classloader的实例方法getResource(String name)会在所引用类加载器使用路径中搜索指定资源的URL
从URL获取数据
public InputStream openStream() throws IOException;
使用案例:
try{ URL u = new URL("http://www.lolcats.com"); try (InputStream in = u.openStream()){ int c; while((c=in.read())!=-1) System.out.write(c); }} catch(IOException ex){ System.out.println(ex);}
显示一个html页面(这里默认为ASCII码字符,实际上html是存在多种编码的)
public class SourceViewer { public static void main(String[] args) { if (args.length > 0) { InputStream in = null; try { URL u = new URL(args[0]); in = u.openStream(); in = new BufferedInputStream(in); Reader r = new InputStreamReader(in); int c ; while ((c = r.read()) != -1) { System.out.println((char) c); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } } }}
public URLConnection openConnection() throws IOException
该方法为指定的URL打开一个socket,并返回一个URLConneciotn对象。该对象表示一个网络资源的打开的链接,如果失败将会抛出异常。如果希望与服务器直接通信,应当使用这个方法,除了访问原始的文档本身外,它还能访问这个协议指定的元数据,例如HTML的首部。
该方法用一个重载的版本:
可以指定哪个代理服务器传递连接
public URLConnection openConnection(Proxy proxy) throws IOException
public final Object getContent() throws IOException
通过URL数据建立对象,如果URL指示的是某中文本,返回的通常是某种InputStream。如果指示一个图像,返回一个java.awt.ImageProducer对象(getContent会从服务器获取的首部查找Content-type字段,如果服务器没有使用MIME首部,或者是不熟悉的Content-type就返回InputStream)
public final Object getContent(Class[] classes) throws IOException
上面方法的重载版本,允许选择返回的类(多个类,返回第一个匹配项),常配合instanceof来使用
分解URL
URL由以下5部分组成:模式;授权机构;路径;片段标识符;查询字符串
授权机构可以进一步分为:用户信息,主机和端口 例如:http://admin@www.blackstar.com:8080/
URL类提供了9个方法访问这些数据:
public String getProtocol();public String getHost();public int getPort();//没有指定端口,就返回-1public int getDefaultPort();public String getFile();//主机名后的都是filepublic String getPath();//不包括查询字符串public String getRef();//返回片段标识符public String getQuery();public String getUserInfo();//返回@符号之前的用户信息public String getAuthority();
equals和hashcode
仅当两个URL都指向相同的主机、端口和路径上的相同资源,而且有相同的片段标识符和查询字符串,才认为两个URL是相等的。不过,equals会尝试用DNS解析主机,来判断连个主机是否相同。这说明URL是一个阻塞的IO操作,因此要避免在HashMap等依赖equals的数据结构中使用(一般情况下应该使用URI来存)。
public boolean sameFile(URL other)
也是比较URL,也会进行DNS查询,但不会比较片段标识符
转换
URL有三个方法可以将一个实例转换为另一种形式,分别是:
toString() toExternalForm() 可以在浏览器中打开toURI()
URI类
URI是对URL的抽象,不仅包括URL,还包括URN(统一资源名),实际上大多URI就是URL。两者的区别有
URI类只和资源的标识和URI的解析有关,没有提供获取RUI所标识资源的方法相比URI类,URI与相关的规范更一致URI对象可以表示相对URI,URL类在存储URI之前会将其绝对化
构造
与URL不同,URI类不依赖于底层协议处理器。只要URI语法正确,java就不需要为了创建URI对象而理解其协议。
public URI(String uri) throws URISyntaxException;public URI(String scheme, String schemeSpecificPart, String fragment) throw...;public URI(String shceme, String host, String path, String fragment) throws ...;public URI(String scheme, String authority, String path, String query, String fragment) throws ...;public URI(String scheme, String userInfo, String host, int port, String path,String query, String fragment) throws URISyntaxException;
上面方法中任何参数都可以省略,从而忽略该参数
URI的各部分
URI的引用主要包括三个部分:模式、模式特定部分、片段标识符
如果省略模式,表示这是一个相对URI,如果省略片段标识符,这个URI就是一个纯URI。
主要方法如下:
public Sting getScheme();public String getSchemeSpecificPart();public String getRawSchemeSpecificPart();public String getFragment();public String getRawFragment();
带raw的是编码形式,不带raw的是对所有用百分号转义的字符进行解码,然后返回。scheme只有ASCII码形式。
有模式的URI是绝对URI,没有模式的是相对URI
public boolean isAbsolute();//判断是不是绝对URIpublic boolean isOpaque();//是否 不是有层次的URI
如果是有层次的,有相关的获取相应部分的方法:
public String getAuthority();public String getFragment();public String getHost();public String getPath();public String getPort();public String getQuery();public String getUserInfo();
这些都是解码后,也就是百分号转义会改为它们实际表示的字符,如果希望得到原始的部分,在get后面加上Raw,注意,host和Port(返回-1表示省略端口)没有raw方法,因为都是由ASCII码组成的
java并不是在开始就检测授权机构部分中的语法错误,所以无法返回授权机构的各个部分:端口、主机、用户信息。可以调用parseServerAuthority()强制重新解析授权机构。(注意URI是final类)
解析相对URI
public URI resolve(URI uri);public URI resolve(String uri);public URI relative(String uri);
相对URI构造绝对URI:
URI absolute = new URI("http://www.example.com");URI relative = new URI("images/logo.png");URI resolved = absolute.resolve(relative);
当然也可以通过相对URI构造相对URI
绝对URI构造相对URI:
URI absolute = new URI("http;//www.example.com/images/logo.png");URI top = new URI("http://www.example.com/");URI relative = top.relativize(absolute);
equals
在进行equals比较时,相等的URI必须都是层次或非层次的,模式和授权机构不会区分大小写,转义字符在比较前不解码
URI实现了Comparable,一次URI可以排序。
字符串表示
toString() 未编码的字符串形式,更方便阅读,但显示结果不能保证是一个语法正确的URI
toASCIIString() 编码后的字符串形式,推荐使用
URLEncoder
对字符串完成URL编码
例如:
String encoded = URLEncoder.encode("this*string*has*asterisks","UTF-8");
注意这个方法对于/,&,=,: 都进行了编码,因此有时候需要分部分的编码(只编码需要编码的,而不是整个URL一起编码)
URLDEcoder
public static String decode(String s, String encoding) throws UnsupportedEncodingException;
该方法可以传入整个URL
代理
Proxy类有三种代理:
Proxy.Type.DIRECT //实际就是没代理Proxy.Type.HTTPProxy.Type.SOCKS
代理信息可以用SocketAddress对象表示:
SocktAddress address - new InetSocketAddress("proxy.example.com",80);Proxy proxy = new Proxy(Proxy.Type.HTTP, address);
每个运行中的虚拟机都有一个Java.net.ProxySelector对象,可以使用自己的ProxySelector子类来替代默认的选择器
ProxySelector类可以根据URI返回合适的代理:
public abstarct list<Proxy> select(URI uri);//返回代理public void connectFailed(URI uri, SocketAddress sa, IOException ioe);//同时必须实现这个连接失败的方法
案例:
public class LocalProxySelector extends ProxySelector { private List<URI> failed = new ArrayList<>(); @Override public List<Proxy> select(URI uri) { List<Proxy> result = new ArrayList<>(); if (failed.contains(uri) || !"http".equalsIgnoreCase(uri.getScheme())) { result.add(Proxy.NO_PROXY); } else { SocketAddress proxyAddress = new InetSocketAddress("proxy.example.com", 80); Proxy proxy = new Proxy(Proxy.Type.HTTP, proxyAddress); result.add(proxy); } return result; } @Override public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { failed.add(uri); }}
改变虚拟机默认的选择器:
ProxySelector selector = new LocalProxySelector();ProxySelector.setDefault(seletor);
因为虚拟机只有一个ProxySelector,因此不推荐在共享的环境下使用这个方法
- Java网络编程之URL和URI
- Java网络编程之URI、URL研究
- Java网络编程URL和URI
- Java网络编程URL和URI
- 读书笔记-java网络编程-5URL和URI-URI类
- 读书笔记-java网络编程-5URL和URI-URL类
- Java网络编程之URI、URL研究(上)
- Java网络编程之URI、URL研究(下)
- Java网络编程之URI、URL研究(下) 01
- Java网络编程之URI、URL研究(下) 03
- 读书笔记-java网络编程-5URL和URI-简述
- 读书笔记-java网络编程-5URL和URI-代理
- 读书笔记-java网络编程-6URL和URI-HTTP协议和cookie的java实现
- 【Java8网络编程】第2章.Java中的URL和URI
- 读书笔记-java网络编程-5URL和URI-x-www-form-urlencoded
- Java URL和URI
- [网络编程学习笔记]Web 概念:URI,URN和URL
- Java网络编程之URL
- iOS之CALayer与核心动画(一)
- Qt5.7连接MYSQL
- MYSQL 合并查询
- 阶乘之和——第28届ACM/ICPC亚洲预赛
- 23种设计模式(3):抽象工厂模式
- Java网络编程之URL和URI
- radio RDS功能简介
- find、findIndex、forEach
- Jquery密码强度验证控件
- fork函数
- iOS之CALayer与核心动画(二)
- JavaSE面试常问(1)
- tensorlayer layer加载model.npz
- python2.7中Matplotlib的安装和应用