URL:统一资源定位符
URI:统一资源标志符
URL与URI很像,两者的格式几乎差不多,但是我们接触的还是URL比较多,就以URL为例说明
URL提供了一种访问定位因特网上任意资源的手段,但是这些资源可以通过不同的方法来访问
获取资源使用的协议,例如:http、ftp等,没有默认值
用户名与密码,这个是一个特殊的存在,一般访问ftp时会用到,她显示的表明了访问资源的用户名和密码。但是这个可以不写,不写的话可能会让你输入用户名密码
主机,访问的那台主机,有时候可以是IP,有时候是主机名,例如www.baidu.com
端口,访问主机时的端口,如果http访问默认80,可以省略
通过host:port我们能找到主机,但是主机上文件很多,通过path则可能定位具体文件
主要作用就是向服务器提供额外的参数,用来表示本次请求的一些特性
例如ftp传输模式有两种,二进制和文本,type=d
通过get方式请求的参数
例如:www.qiandu.com/index.html?username=dgh&passwd=123
当html页面比较长时,我们通常会将其分为好几段,#1就可以快速定位到某一段
URI的组成测试
import java.net.*;
public class uriTest {
public static void main(String[] args) throws Exception{
URI uri = new URI("http://www.qiandu.com:8080/goods/index.html?username=dgh&passwd=123#j2se");
System.out.println("scheme :"+uri.getScheme());
System.out.println("schemeSpecificPart :"+uri.getSchemeSpecificPart());
System.out.println("Authority :"+uri.getAuthority());
System.out.println("host :"+uri.getHost());
System.out.println("port :"+uri.getPort());
System.out.println("path :"+uri.getPath());
System.out.println("query :"+uri.getQuery());
System.out.println("fragment :"+uri.getFragment());
}
}
URL测试组成
import java.net.*;
public class urlTest {
public static void main(String[] args) throws Exception{
URL url = new URL("http://www.qiandu.com:8080/goods/index.html?username=dgh&passwd=123#j2se");
System.out.println("URL :"+url.toString());
System.out.println("protocol :"+url.getProtocol());
System.out.println("Authority :"+url.getAuthority());
System.out.println("file name :"+url.getFile());
System.out.println("host :"+url.getHost());
System.out.println("port :"+url.getPort());
System.out.println("path :"+url.getPath());
System.out.println("query :"+url.getQuery());
System.out.println("default port :"+url.getDefaultPort());
System.out.println("ref :"+url.getRef());
}
}
其实关于资源定位的时候还有一种写法,就是在主机名前面有类似于xx@的东西,其实这种表示就:用户@主机名或者用户@IP。@前面表示登录主机的用户,也就是UserInfo了
import java.net.*;
public class userInfo {
public static void main(String[] args) throws Exception{
URL url = new URL("https://[email protected]");
System.out.println("UserInfo:"+url.getUserInfo());
}
}
java.net.URL类是JAVA对URL的抽象,是一个final类,不能被继承。实际上URL类使用了策略设计模式,通过不同的协议处理器来扩展功能
URL类是不可变的,对象构建完成后,字段就无法改变,因此能够保证线程安全
URL类提供了多种构造器,用于在不同情况下创建对象
public URL(string url)throws MalformedURLException
根据一个字符串形式的绝对URL构建URL对象。如果构造成功,说明URL的协议得到了支持。
失败则会抛出MalformedURLException异常
import java.net.*;
public class testProtocol {
public static void testProtocol(String url){
try{
URL u = new URL(url);
System.out.println(u.getProtocol()+"is supported.");
}catch(MalformedURLException e) {
String protocol = url.substring(0, url.indexOf(":"));
System.out.println(protocol + " is supported.");
}
}
public static void main(String[] args) {
testProtocol("http://www.baidu.com");
}
}
public URL(String protocol,String host,String file)throws MalformedURLEception
public URL(String protocol,String host,int port,String file)throws MalformedURLException
public URL(URL context,String spec)throws MalformedURLException
这个构造器根据基础URL和相对URL构建URL对象。简单来讲,就是用spec(相对URL)中的信息替换掉context(基础URL)中的对应部分
import java.net.*;
public class protocolHostTest {
public static void main(String[] args) throws Exception{
URL url = new URL("http","osu.ppy.sh","/s/557145");
URL url2 = new URL(url,"625822");
URL url3 = new URL(url,"/p/beatmaplist");
System.out.println(url);
System.out.println(url2);
System.out.println(url3);
}
}
openStream()方法是最直接的,它能够打开到指定URL的连接,并返回一个InputStream,从这个InputStream获得的数据是URL引用的原始内容,因此可能是ASCII文本,HTML、二进制图片数据等
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
public class openStreamDemo {
public static void showWebSourceCode(String url){
try{
URL u = new URL(url);
try(BufferedReader reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(u.openStream()),"UTF-8"))){
String line;
while((line = reader.readLine())!= null){
System.out.println(line);
}
}catch (IOException e){
e.printStackTrace();
}
}catch(MalformedURLException e){
System.out.println("Fail to connect to the url.");
}
}
public static void main(String[] args) {
showWebSourceCode("https://www.baidu.com/");
}
}
记得url最前面加上http://
getContent()方法获取由URL引用的数据,尝试由它建立某种类型的对象。返回的对象可能是InputStream、HttpURLConnection、sun.awt.image.URLImageSource等等
getContent(Class[] classes)接受一个class数组,用于选择最合适的返回类型。它会从数组的第一个开始判断,如果能够返回该类型则返回该类型,否则判断下一个,以此类推。注意返回值依然是Object,需要用instanceof判断实际类型
URL分为5个部分:
URL类的equals方法会判断两个URL的各个部分,包括查询字符串和片段标识符,只有全部相等才返回true。需要注意两点:
与equals()方法相似,但sameFile()方法不考虑片段标识符
URL类的toString()方法会返回一个包含绝对URL的字符串
将URL对象转换为对应的URI对象,返回一个对应的URI对象
URI类与URL类的主要区别如下:
URI类同样提供了一系列的构造器,用于根据不同条件创建对象,和URL类在很多方面类似
public URI(String str)throws URISyntaxException
根据字符串创建对象
public URI(String scheme,String ssp,String fragment)throws URISyntaxExeption
根据模式、模式特定部分、片段标识符创建对象
注意:模式可以为null,此时创建的就是相对URI
注意:URI类会对特殊字符自动进行编码
根据传入的不同部分构建URI。参数含义和URL的基本一致,此处不再赘述。唯一需要注意的是,URI类会对特殊字符自动进行编码,但是路径内的“/”会被视作分隔符而不参与编码,此时只能手动处理“/”
所有的构造器在传入的参数格式与URI规范不符时都会抛出一个URISyntaxException异常,这个异常不是运行时异常,因此必须在编译时就进行处理
与URL类相似,URI类也提供了一系列的get方法,用于获取URI的各个组成部分。由于绝大多数部分和URL类相同,此处不再赘述
import java.net.*;
public class URIabsolute {
public static void main(String[] args) throws URISyntaxException{
URI absolute = new URI("https://osu.ppy.sh/s/452625");
URI base = new URI("https://osu.ppy.sh/");
URI relative = base.relativize(absolute);
System.out.println(relative);
System.out.println(base.resolve(relative));
}
}
相对URI
import java.net.URISyntaxException;
import java.net.*;
public class URIbase {
public static void main(String[] args) throws URISyntaxException {
URI base = new URI("https://osu.ppy.sh/");
URI relative = new URI("s/452625");
URI resolved = base.resolve(relative);
System.out.println(resolved);
System.out.println(resolved.resolve(new URI("653523")));
}
}
URI替换
import java.net.URISyntaxException;
import java.net.*;
public class URIrelative {
public static void main(String[] args) throws URISyntaxException {
URI base = new URI("https://osu.ppy.sh/a/b/c/");
String relative = "s/452625";
URI resolved = base.resolve(relative);
System.out.println(resolved);
System.out.println(resolved.resolve("/d/653523"));
}
}
hashCode()方法的相等性与equals()一致
返回URI未编码的字符串形式(尽管实际上经过了编码)。可以使用toASCIIString方法返回URI的编码形式
import java.net.*;
public class toString {
public static void main(String[] args) throws URISyntaxException{
URI uri = new URI("https://www.example.com/s/新年快乐");
System.out.println(uri.toString());
System.out.println(uri.toASCIIString());
}
}
基于字符串的比较,他的排序规则如下:
前面提到过,URL需要对特殊字符进行编码,而中国工作在构建他们的对象时不会自动完成
java提供了URLEncoder与URLDecoder,用于编码和解码
public static String encode(String s,String enc)throws UnsupportedEncodingException
提供了这样一个方法进行编码,第一个参数是需要编码的原始字符串,第二个是字符集,一般都用UTF-8
这个方法的问题在于,它会进行过度编码,实例如下:
String str = URLEncoder.encode("https://www.baidu.com","UTF-8");
System.out.println(str);
可以看到,它把本不需要编码的“/”和“:”都进行了编码。这个问题没有通解,只能通过手工编码将字符串各个部分分别编码,之后再组合起来
public static String decode(String s,String enc)throws UnsupportedEncodingException
通过GET方法与服务端程序通信
有些网站使用了HTTP认证(BASIC认证等),因此在访问之前需要通过认证。