JAVA网络编程个人笔记 第五章 URL和URI

URL和URI

URL/URI简介

URI与URL的定义

URL:统一资源定位符
URI:统一资源标志符

  • URI与URL都是定位资源位置的,就是表示这个资源的位置信息,就像经纬度一样可以表示你在世界的那个角落
  • URI是一种宽泛的含义更广的定义,而URL则是URI的一个子集,就是说URL是URI的一部分
  • 每个URL都是URI,但不是每个URI都是URL
  • URL是可以直接操作的,但是URI并不行
  • 在java.net.URI,只能看到他的一些属性,他只是表示一个表示,但是你没有办法通过URI获取这个对象的流
  • 但是URL不一样。java.net.URL该类提供方法openConnection(),通过该方法我们可以通过IO流操作它

URL的语法

URL与URI很像,两者的格式几乎差不多,但是我们接触的还是URL比较多,就以URL为例说明

URL提供了一种访问定位因特网上任意资源的手段,但是这些资源可以通过不同的方法来访问

不管怎么样,他都基本由9个部分组成:
> ://:@:/;?#

scheme

获取资源使用的协议,例如:http、ftp等,没有默认值

user:password

用户名与密码,这个是一个特殊的存在,一般访问ftp时会用到,她显示的表明了访问资源的用户名和密码。但是这个可以不写,不写的话可能会让你输入用户名密码

host

主机,访问的那台主机,有时候可以是IP,有时候是主机名,例如www.baidu.com

port

端口,访问主机时的端口,如果http访问默认80,可以省略

path

通过host:port我们能找到主机,但是主机上文件很多,通过path则可能定位具体文件

Params

主要作用就是向服务器提供额外的参数,用来表示本次请求的一些特性

例如ftp传输模式有两种,二进制和文本,type=d

query

通过get方式请求的参数
例如:www.qiandu.com/index.html?username=dgh&passwd=123

Fragment

当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());
    }
}

UserInfo属性

其实关于资源定位的时候还有一种写法,就是在主机名前面有类似于xx@的东西,其实这种表示就:用户@主机名或者用户@IP。@前面表示登录主机的用户,也就是UserInfo了

代码实例
import java.net.*;
public class userInfo {
    public static void main(String[] args) throws Exception{
        URL url = new URL("https://denggonghai@www.qiandu.com");
        System.out.println("UserInfo:"+url.getUserInfo());
    }
}

URL类

URL类简介

java.net.URL类是JAVA对URL的抽象,是一个final类,不能被继承。实际上URL类使用了策略设计模式,通过不同的协议处理器来扩展功能

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");
    }

}

由组成部分构建URL对象

public URL(String protocol,String host,String file)throws MalformedURLEception
public URL(String protocol,String host,int port,String file)throws MalformedURLException

  • 两个方法都是利用URL的组成部分来构建URL对象,区别在于有无端口号。如果不设置端口号,构造器会将端口设置为-1,即使用协议的默认端口
  • 此处的protocol和host只要正常填写内容即可,如“http”、“www.csdn.net”,而file需要在开头加上/.file包括路径、文件名和可选片段标识符
根据相对URL构建URL对象

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);
    }
}

从URL对象获取信息

  • public final InputStream openStream() throws java.io.IOException
  • public URLConnection openConnection() throws java.io.IOException
  • public URLConnection openConnection(Proxy proxy) throws java.io.IOException
  • public final Object getContent() throws java.io.IOException
  • public final Object getContent(Class[] classes)throws java.io.IOException
openStream()方法

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://

openConnection方法
  • openConnection方法为指定的URL打开一个Socket,并返回一个URLConnec对象
  • 一个URLConn对象表示一个网络资源的打开的连接。如果需要和服务器通信,这个方法是最好的。
  • 重载版本可以指定一个代理服务器
getContent()方法

getContent()方法获取由URL引用的数据,尝试由它建立某种类型的对象。返回的对象可能是InputStream、HttpURLConnection、sun.awt.image.URLImageSource等等

getContent(Class[] classes)接受一个class数组,用于选择最合适的返回类型。它会从数组的第一个开始判断,如果能够返回该类型则返回该类型,否则判断下一个,以此类推。注意返回值依然是Object,需要用instanceof判断实际类型

分解URL

URL分为5个部分:

  • 模式(协议)
  • 授权结构(主机)
  • 路径
  • 查询字符串
  • 片段标识符(ref)

URL类的Object方法

equals()方法

URL类的equals方法会判断两个URL的各个部分,包括查询字符串和片段标识符,只有全部相等才返回true。需要注意两点:

  1. equals()方法会尝试用DNS查询主机,来判断两个主机是否相同,这导致equals()方法可能阻塞。因此,应避免将URL存储在依赖equals()方法的数据结构里(如hashMap中)
  2. equals不会具体比较URL指向的资源
sameFile()方法

与equals()方法相似,但sameFile()方法不考虑片段标识符

toString()方法

URL类的toString()方法会返回一个包含绝对URL的字符串

toURI()方法

将URL对象转换为对应的URI对象,返回一个对应的URI对象

URI类

URI类简介

URI类与URL类的主要区别如下:

  • URI类只有关于资源的标识和对URI进行解析的方法,没有关于获取URI指向的资源的方法。这是因为URI只能用于标识一个资源,不一定能确定资源在网络上的位置
  • URI对象可以表示相对URI,URL类存储之前会将其绝对化
  • 相比于URL类,URI类与相关规范更加一致
  • 简而言之,如果你需要获取资源,那么应当使用URL类;而如果你只需要标识资源,那么用URI类更加合适

创建URI对象

URI类同样提供了一系列的构造器,用于根据不同条件创建对象,和URL类在很多方面类似

  • public URI(String str)throws URISyntaxException
  • public URI(String scheme,String ssp,String fragment)throws URISyntaxExeption
  • public URI(String scheme,String host,String path,String fragment)throws URISyntaxException
  • public URI(String scheme,String authority,String path,String query,String fragment)throws URISyntaxException
  • public URI(String scheme,String userInfo,String host,int port,String path,String query,String fragment)throws URISynataxException
URI(String str)

public URI(String str)throws URISyntaxException
根据字符串创建对象

URI(String scheme,String ssp,String fragment)

public URI(String scheme,String ssp,String fragment)throws URISyntaxExeption

根据模式、模式特定部分、片段标识符创建对象

注意:模式可以为null,此时创建的就是相对URI
注意:URI类会对特殊字符自动进行编码

根据传入的不同部分构建URI。参数含义和URL的基本一致,此处不再赘述。唯一需要注意的是,URI类会对特殊字符自动进行编码,但是路径内的“/”会被视作分隔符而不参与编码,此时只能手动处理“/”

所有的构造器在传入的参数格式与URI规范不符时都会抛出一个URISyntaxException异常,这个异常不是运行时异常,因此必须在编译时就进行处理

与URL类相似,URI类也提供了一系列的get方法,用于获取URI的各个组成部分。由于绝大多数部分和URL类相同,此处不再赘述

和URL类的几点区别:
  • isAbsolute():判断是否绝对URI,若是则返回true。判断依据是URI的模式(scheme)是否为null
  • isOpaque():判断是否是不透明的,若是则返回true。不透明的URI只能得到模式、模式特定部分和片段标识符。层次URI是透明的
  • URI类的许多getxxx方法都一个getRawXXX版本,区别在于getXXX返回解码后的结果,而getRawXXX返回未解码的结果

在这里插入图片描述

解析相对URI

  • 相对URI转绝对URI
    • public URI resolve(URI uri)
    • public URI resolve(String uri)
  • 绝对URI转相对URI
    • public URI relativize(URI uri)
代码实现
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"));
    }
}

URI相等性和比较

equals()方法
  • URL的equals()方法不是单纯地比较字符串。两个URI要相等,首先它们必须都是层次的或都是不透明的
  • 比较模式(scheme)和主机(host)时不区分大小写(HTTP和http相同,www.baidu.com和www.BAIDU.com相同)
hashCode()方法

hashCode()方法的相等性与equals()一致

toString()方法

返回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());
    }
}

Comparable接口

基于字符串的比较,他的排序规则如下:

  • 如果模式不同则比较模式,不考虑大小写
  • 若模式相同则观察两个URI是否有层次,一般认为层次URI不小于不透明URI
  • 若都是不透明URI则根据模式特定部分排序;若模式特定部分也相同则根据片段排序
  • 若都是层次URI,则根据授权机构排序。授权机构本身按照用户信息、主机和端口排序,比较主机时不区分大小写;如果模式和授权机构都相等,则根据路径排序;路径相等则根据查询字符串排序;查询字符串相等则根据片段排序;URI只能和URI比较,否则会抛出ClassCastException异常

URLEncoder与URLDecoder

前面提到过,URL需要对特殊字符进行编码,而中国工作在构建他们的对象时不会自动完成

java提供了URLEncoder与URLDecoder,用于编码和解码

URIEncoder

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);

可以看到,它把本不需要编码的“/”和“:”都进行了编码。这个问题没有通解,只能通过手工编码将字符串各个部分分别编码,之后再组合起来

Decoder

public static String decode(String s,String enc)throws UnsupportedEncodingException

  • 参数化意义和URLEncoder相同,第一个参数是需要编码的原始字符串,第二个是字符集,一般都用UTF-8
  • 使用这个方法的时候不需要拆分,只需要将整个字符串即可,这是因为它不会对非转义字符做任何处理,只会把+号替换为空格,以及将%XX转换为对应的字符

通过GET方法与服务器端程序通信

通过GET方法与服务端程序通信

  • URL类使得和使用GET方法的服务器端程序通信非常容易。需要做的事情只有根据网站的表单构造查询字符串,然后拼接到URL上即可。所有查询字符串的名和值必须通过编码
  • 关于然后获取网站表单所需的参数,可以利用浏览器的调试功能找到对应表单的源代码,从中可以获知相关信息

访问口令保护的网站

有些网站使用了HTTP认证(BASIC认证等),因此在访问之前需要通过认证。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java网络编程是一种通过使用Java编程语言,在计算机网络上实现通信的技术。它涉及到协议、IP地址和端口号等三个重要要素。Java编写的应用程序可以在单个计算机上运行,也可以在网络的服务器端和客户端上分布运行。此外,Java还可以用于编写小型应用程序模块或applet,作为网页的一部分使用。applet可以嵌入网页,并在浏览器运行。在Java,使用URI可以代表绝对的或相对的资源,而URL则包含了定位资源的信息,并且不能是相对的。Java提供了一系列的和接口,例如InetAddress、Socket、ServerSocket、URLURLConnection等,用于实现各种网络应用。通过使用这些和接口,可以创建连接客户端和服务器之间的套接字,并实现面向连接的通信,保证数据的可靠传输。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Java网络编程](https://blog.csdn.net/weixin_42784609/article/details/130388655)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [超详细入门到精通自学视频课程(阶段01:JavaSE基础02 编程思维编程思维和编程能力、综合应用专题-04、案例...](https://download.csdn.net/download/weixin_54787054/88224199)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [网络编程](https://blog.csdn.net/zhixingwu/article/details/103226003)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值