URL的全称是Uniform Resource Locator,意思是统一资源定位符,俗称网络地址或网址。网络上的每个文件及接口,都有对应的URL网址,它规定了其他设备如何通过一系列的路径找到自己,犹如网购的包裹一路送至收货地址所描述的地点。现实生活中的通讯地址,一般遵循固定的格式,比如“××省××市××区××小区×××”;网络地址也有相应的命名规则,比如新华网的首页地址为“http://www.news.cn”,当然该地址比较简单,还能造出更复杂的URL如“http://www.news.cn:8080/Public/GetValidateCode?time=123#index”(该网址纯属虚构)。虽然普通用户平时上网只消打开网页接着在各类链接之间跳来跳去,但是作为程序员必须弄清楚这些链接地址的格式涵义,这样才能学好网络通信的编程开发。仍以网址“http://www.news.cn:8080/Public/GetValidateCode?time=123#index”为例,该URL包含了网络地址的各项组成部分,具体细节如下图所示。


接下来对上图的URL字符串补充详细说明,从左到右依序介绍如下:
1、最开头的http表示该地址采用的网络协议,它的全称是“Hypertext Transfer Protocol”,意思是超文本传输协议。除了http,常见的网络协议还有https、ftp、file、telnet等等。
2、协议后面越过两个斜杆,紧跟着的是该网址所在的域名,也叫主机名称。这块早已为大众所熟知,除了新华网的www.news.cn,还有中央电视台的www.cctv.com、人民日报的www.people.com.cn等等。
3、域名后面以冒号隔开的数字叫做端口号,像http协议默认的端口号是80。如果该网址采取默认的端口,就不必写明端口数字;如果该网址使用了非默认的端口,比如http服务搭建在8080端口之上,就必须在URL中写明8080。
4、域名加上端口号,组成了URL的授权部分,即网址的入口。
5、授权部分的右边包括斜杆在内、问号之前的一长串字符,表示具体的网络路径,犹如操作系统里面的文件目录。
6、问号之后、井号之前的部分,是以等号隔开的请求参数,各参数之间以“&”分隔,具体格式形如“参数A名称=A参数值&参数B名称=B参数值&参数C名称=C参数值”。请求参数中的参数值允许变化,网络服务将按照指定的数值返回相应的结果数据。
7、网络路径加上请求参数,组成了URL的文件名称,有了文件名就能访问该URL所表达的网络资源。
8、井号之后的字串为引用位置,假设一个网页很长很长,打开后默认显示网页的顶部,造成用户下拉网页找到某块区域有点麻烦。而引用位置先给各区域做个编号,然后在URL末尾带上该位置的编号,于是网页打开后会自动滚到指定位置的区域,从而方便了用户的浏览操作。
搞清楚了URL各段部分的作用,有助于后续的网络编程工作。就网址访问而言,Java提供了同名的网址工具URL,该工具类不偏不倚正好名叫URL,其构造方法的输入参数即为网址字符串,此后的HTTP访问操作皆有赖于URL对象。URL工具常用的方法包括但不限于下列几种:
getProtocol:获取URL对象采用的网络协议。
getHost:获取URL对象的域名(主机名称)。
getDefaultPort:获取URL对象的默认端口。http协议的默认端口号是80,ftp协议的默认端口号是21,https协议的默认端口号是443。
getPort:获取URL对象的指定端口(若不显式指定则返回-1)。
getAuthority:获取URL对象的授权部门(由域名和指定端口组成)。
getPath:获取URL对象的路径(不包括域名)。
getQuery:获取URL对象的请求参数。
getFile:获取URL对象的文件名(由路径和请求参数组成)。
getRef:获取URL对象的引用位置。
openConnection:打开URL对象的网络连接,并返回URLConnection连接对象。无论是接口调用,还是上传下载,都依赖于这里的连接对象。

一个完整的网址字符串,包含了蛮多的地址信息,一个字符都错不得。自然程序员很关心网址到底有哪些校验办法,可以支持判断某个网址是合法请求还是非法请求。首先是域名的合法性校验,Java提供了专门的网络地址工具InetAddress,调用该工具的静态方法getByName,能够获得指定域名的网络地址对象,具体的方法调用代码示例如下:

			// 根据域名或IP获得对应的网络地址对象
InetAddress inet = InetAddress.getByName(host);

之后调用网络地址对象的以下方法,即可获取相应的网络地址信息:
getHostAddress:获取网络地址对象的IP地址。
getHostName:获取网络地址对象的域名。
isReachable:检查对方主机是否能连得上。但该方法不可靠,因为可能由于存在防火墙导致返回false。
可见尽管InetAddress提供了isReachable方法用于检测域名的连通性,但该方法并不总能奏效。那么退而求其次,只要校验域名的格式是否正确便行;这样的话,在调用getByName方法之时,增加捕捉未知域名异常UnknownHostException;一旦捕捉到该异常,就认为当前域名是非法域名。此时域名的合法性校验代码变成了下面这样:

	// 测试域名的可用信息。返回true表示域名合法,返回false表示域名非法
private static boolean testHost(String host) {
try {
// 根据域名或IP获得对应的网络地址对象
InetAddress inet = InetAddress.getByName(host);
} catch (UnknownHostException e) { // 如果host字符串并非合法的域名/IP,则getByName方法会扔出“未知的域名异常”
e.printStackTrace();
return false; // 返回false表示该字符串不是合法的域名/IP
}
return true; // 返回true表示该字符串是合法的域名/IP
}

另一个值得注意的地方是请求参数中的参数值编码,显然URL格式存在部分保留字符,包括冒号、斜杆、问号、井号等等,这些字符不应直接出现在Query部分的参数值当中,故而需要对参数值里面的保留字符进行转义。常见字符对应的URL转义符如下图所示:


除了保留字符以外,中文字符一样需要转义,比如“你”要转为“%E4%BD%A0”。原始字符的转义过程也称作URL编码,反过来则有反转义过程,即将转义后的字符恢复为原始字符,反转义过程也称作URL解码。Java同时提供了对应的URL编码工具URLEncoder,以及URL解码工具URLDecoder,其中URL编码的方法调用示例如下:

		// 获得URL编码后的转义字符串
String encoded = URLEncoder.encode(origin);

URL解码的方法调用示例如下:

		// 获得URL解码后的原始字符串
String origin = URLDecoder.decode(encoded);


更多Java技术文章参见《Java开发笔记(序)章节目录

Java开发笔记(一百零七)URL地址的组成格式的更多相关文章

  1. Java开发笔记(一百零一)通过加解锁避免资源冲突

    前面介绍了如何通过线程同步来避免多线程并发的资源冲突问题,然而添加synchronized的方式只在简单场合够用,在一些高级场合就暴露出它的局限性,包括但不限于下列几点:1.synchronized必 ...

  2. Java开发笔记(一百零九)XML报文的定义和解析

    前面介绍了JSON格式的报文解析,虽然json串短小精悍,也能有效表达层次结构,但是每个元素只能找到对应的元素值,不能体现更丰富的样式特征.比如某个元素除了要传输它的字符串文本,还想传输该文本的类型. ...

  3. Java开发笔记(一百零四)普通线程池的运用

    前面介绍了线程的基本用法,以及多线程并发的问题处理,但实际开发中往往存在许多性质相似的任务,比如批量发送消息.批量下载文件.批量进行交易等等.这些同类任务的处理流程一致,不存在资源共享问题,相互之间也 ...

  4. Java开发笔记(一百零三)线程间的通信方式

    前面介绍了多线程并发之时的资源抢占情况,以及利用同步.加锁.信号量等机制解决资源冲突问题,不过这些机制只适合同一资源的共享分配,并未涉及到某件事由的前因后果.日常生活中,经常存在两个前后关联的事务,像 ...

  5. Java开发笔记(一百零二)信号量的请求与释放

    前面介绍了同步与加锁两种并发处理机制,虽然加锁比起同步要灵活一些,但是加锁在某些高级场合依然力有未逮,包括但不限于下列几点:1.某块代码被加锁之后,对其它线程而言就处于繁忙状态,缺乏弹性的阈值范围:2 ...

  6. Java开发笔记(一百零五)几种定时器线程池

    前面介绍了普通线程池的用法,就大多数任务而言,它们对具体的执行时机并无特殊要求,最多是希望早点跑完早点出结果.不过对于需要定时执行的任务来说,它们要求在特定的时间点运行,并且往往不止运行一次,还要周期 ...

  7. Java开发笔记(一百零六)Fork+Join框架实现分而治之

    前面依次介绍了普通线程池和定时器线程池的用法,这两种线程池有个共同点,就是线程池的内部线程之间并无什么关联,然而某些情况下的各线程间存在着前因后果关系.譬如人口普查工作,大家都知道我国总人口为14亿左 ...

  8. Java开发笔记(七十三)常见的程序异常

    一个程序开发出来之后,无论是用户还是程序员,都希望它稳定地运行,然而程序毕竟是人写的,人无完人哪能不犯点错误呢?就算事先考虑得天衣无缝,揣着一笔巨款跑去岛国买了栋抗震性能良好的海边别墅,谁料人算不如天 ...

  9. Java开发笔记(一百二十八)Swing的图标

    前面提过,AWT没提供能够直接显示图像的控件,这无疑是个令人诟病的短板,因为一上来就得由程序员自己去定义新控件,对于初学者来讲很不友好.这个问题在Swing中也解决掉了,不过Swing并未提供单独的图 ...

随机推荐

  1. [Go] Slices vs Array

    It is recommended to use 'slice' over 'Array'. An array variable denotes the entire array; it is not ...

  2. 在x64计算机上捕获32位进程的内存转储

    这是一个我经常遇到的问题,我们经常会遇到这样的情况:我们必须重新捕获内存转储,因为内存转储是以“错误”的方式捕获的.简而言之:如果在64位计算机上执行32位进程,则需要使用允许创建32位转储的工具捕获 ...

  3. WinDbg常用命令系列---.load, .loadby (Load Extension DLL)

    .load, .loadby (Load Extension DLL) 简介 .load和.loadby命令将新的扩展DLL加载到调试器中. 使用形式 .load DLLName !DLLName.l ...

  4. Windows是如何将64位Ntdll映射到32位进程的---转自简书

    今天我们探索一个问题: 64位的ntdll是如何被加载到WoW64下的32位进程?今天的旅程将会带领我们进入到Windows内核逻辑中的未知领域,我们将会发现32位进程的内存地址空间是如何被初始化的. ...

  5. 洛谷 P4779 【模板】单源最短路径(标准版) 题解

    P4779 [模板]单源最短路径(标准版) 题目背景 2018 年 7 月 19 日,某位同学在 NOI Day 1 T1 归程 一题里非常熟练地使用了一个广为人知的算法求最短路. 然后呢? 100 ...

  6. 微信小程序七夕节礼物

    VSCode Node.js HbuilderX 安装前端开发环境 [外链图片转存失败(img-aXUJRfXc-1565136341881)(https://upload-images.jiansh ...

  7. mysql ,with rollup的用法

    如下,可以看到使用后,也统计了null的个数. mysql> select * from table1; +----------+------------+-----+------------- ...

  8. Maven中使用<version>LATEST</version>自动依赖最新版本引发的问题

    今天在打包项目的过程中出现了编译问题,奇怪的是这个项目已经好久没有修改过了,报错如下. 找不到符号 [ERROR] 符号: 方法 intent(java.lang.String) [ERROR] 位置 ...

  9. 公司不用 Spring Boot,果断离职了!

    面试问到离职原因,我想这是很多面试者的痛,包括我自己,曾经也被离职原因所坑过. 面试回答离职原因简直特么就是巨坑,我也因此在微信公众号 "Java技术栈" 写了这篇文章<过了 ...

  10. 解决Bootstrap标签页(Tab)插件切换echarts不显示问题

    1.参考连接:https://blog.csdn.net/qq_24313955/article/details/78363981 问题描述:在echarts跟bootstrap选项卡整合的时候,默认 ...