什么是 URI?URI 和 URL 的区别是?URI 的编码方法?

如果不知道的话就往下看看吧~

什么是 URI

URI (Uniform Resource Identifier),也就是 统一资源标识符 。

它的 作用 就是区分互联网上不同的资源。

URI 包括两个部分:

  • URL  (Uniform Resource Location),统一资源定位符 。
  • URN (Uniform Resource Name),统一资源名称 。

URI 的 结构:

scheme :// user:passwd @ host:port path ? query #fragment

scheme 表示协议名,比如 http , https , file 等等。后面必须和 ://连在一起。协议可以自定义。

user:passwd@ 表示登陆主机时的用户名和密码,不过很不安全,不推荐使用,也不常用。

host:port 表示主机名和端口。

path 表示请求路径,标记资源所在位置。

query 表示查询参数 ,以? 开始,为 key = val 键值对的形式 ,以 & 隔开。

fragment 也叫哈希。表示 URI 所定位的资源内的一个锚点,浏览器可以根据这个锚点跳转到对应位置。

例子:

https://www.baidu.com/s?wd=HTTP&rsv_spt=1#heading-8复制代码

https 即 scheme 协议

www.baidu.com 即 host:port 主机名和端口。注意,http 和 https 的默认端口分别是80、443。

/s 即 path 请求路径,标记资源所在位置。

wd=HTTP&rsv_spt=1 即 query 参数部分,且为两个。

heading-8 即 fragment  锚点。

URL 为 https://www.baidu.com/s?wd=HTTP&rsv_spt=1

URN 为 www.baidu.com/s?wd=HTTP&rsv_spt=1#heading-8

URI 编码方法

URI 只能使用ASCII, ASCII 之外的字符是不支持显示的,而且还有一部分符号是界定符,如果不加以处理就会导致解析出错。

因此,URI 引入了 编码机制 ,将所有非 ASCII 码字符和界定符转为十六进制字节值,然后在前面加个%。

如,空格被转义成了%20,布纳纳被转义成了 %E5%B8%83%E7%BA%B3%E7%BA%B3。

encodeURI() 和 encodeURIComponent()

encodeURI() 和 encodeURIComponent() 方法用于编码统一资源标识符(URI),以便传给浏览器。

  • encodeURI()方法用于对整个 URI 进行编码
  • encodeURIComponent() 方法用于编码 URI 中单独的组件,
let uri = "https://zhuanlan.zhihu.com/p/40311981?redirect=a"console.log(encodeURI(uri))// https://zhuanlan.zhihu.com/p/40311981?redirect=a// 使用 encodeURI()编码后,除空格被替换为%20 之外,没有任何变化。console.log(encodeURIComponent(uri))// https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F40311981%3Fredirect%3Da// encodeURIComponent()方法将所有非字母字符都替换成了相应的编码形式。复制代码

因此,我们发现这两个方法的 主要区别 是:encodeURI() 不会编码属于 URL 组件的特殊字符,比如冒号、斜杠、问号、 井号,而 encodeURIComponent() 会编码它发现的所有非标准字符。这就是使用 encodeURI() 编码整个 URI,但只使用 encodeURIComponent() 编码那些会追加到已有 URI 后面的字符串的原因。

注意 一般来说,使用 encodeURIComponent() 比使用 encodeURI() 的频率更高, 这是因为编码查询字符串参数比编码基准 URI 的次数更多。

decodeURI() 和  decodeURIComponent()

  • decodeURI() 只对使用 encodeURI() 编码过的 字符解码。

  • 同样,decodeURIComponent() 只对使用 encodeURIComponent() 编码过的字符解码 ,基本上就是解码所有特殊值。

例子:

let uri = "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.js%23start";console.log(decodeURI(uri));// http%3A%2F%2Fwww.wrox.com%2Fillegal value.js%23startconsole.log(decodeURIComponent(uri)); 
// http:// www.wrox.com/illegal value.js#start复制代码

这里,uri 变量中包含一个使用 encodeURIComponent()编码过的字符串。

首先输出的是使用 decodeURI() 解码的结果,可以看到只用空格替换了%20 。

然后是使用 decodeURIComponent() 解码的 结果,其中替换了所有特殊字符,并输出了没有包含任何转义的字符串。(这个字符串不是有效的 URL。)

如何获取 URI 参数?

// 1.取 ? 开头,# 结尾 的字符串// 2.根据 & 分割参数// 3.根据 = 分割键值对function getParams(str){  // ? 的索引
  const startIdx = str.indexOf('?') + 1;  const endIdx = str.indexOf('#')  const paramString = str.substring(startIdx ,endIdx);  console.log('paramString:' + paramString)  
  const kvArr = paramString.split('&');  console.log('kvArr:' + kvArr)  
  const params = {};
  
  kvArr.forEach(item =>{const [k,v] = item.split('=');
    params[k] = v;
  });  return params;
}console.log(getParams('https://zhuanlan.zhihu.com/p/40311981?redirect=a&param=b#heading-8'));复制代码

https://zhuanlan.zhihu.com/p/40311981?redirect=https://www.baidu.com?a=10&param=b#heading-8 的参数是?

console.log(getParams('https://zhuanlan.zhihu.com/p/40311981?redirect=https://www.baidu.com?a=10&param=b#heading-8'));// {redirect: "https://www.baidu.com?a", param: "b"}复制代码

这明显不对, redirect 的值应该是 https://www.baidu.com?a=10 。解决:

let redirect = "https://www.baidu.com?a"let uri = `https://zhuanlan.zhihu.com/p/40311981?redirect=${encodeURIComponent(redirect)}&param=b#heading-8`console.log(getParams(uri))复制代码

如果想让参数只有 redirect 且值是 https://www.baidu.com?a=10&param=b呢?

let redirect1 = "https://www.baidu.com?a=10&param=b"let uri1 = `https://zhuanlan.zhihu.com/p/40311981?redirect=${encodeURIComponent(redirect1)}#heading-8`console.log(getParams(uri1))复制代码

最后

如有问题请大佬指正~

如有帮助,希望能够点赞收藏~