你必须知道的 URI

665 阅读3分钟

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

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

什么是 URI

URIUniform 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

httpsscheme 协议

www.baidu.comhost:port 主机名和端口。注意,httphttps 的默认端口分别是80、443。

/spath 请求路径,标记资源所在位置。

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

heading-8fragment 锚点。

URLhttps://www.baidu.com/s?wd=HTTP&rsv_spt=1

URNwww.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%23start

console.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))

最后

如有问题请大佬指正~

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

参考资料: