【基础进阶】URL详解与URL编码

作为前端,每日与 URL 打交道是必不可少的。但是也许每天只是单纯的用,对其只是一知半解,随着工作的展开,我发现在日常抓包调试,接口调用,浏览器兼容等许多方面,不深入去理解URL与URL编码则会踩到很多坑。故写下此篇文章,详解一下 URL 。

   URL 与 URI

很多人会混淆这两个名词。

URL:(Uniform/Universal Resource Locator 的缩写,统一资源定位符)。

URI:(Uniform Resource Identifier 的缩写,统一资源标识符)。

关系:

URI 属于 URL 更低层次的抽象,一种字符串文本标准。

就是说,URI 属于父类,而 URL 属于 URI 的子类。URL 是 URI 的一个子集。

二者的区别在于,URI 表示请求服务器的路径,定义这么一个资源。而 URL 同时说明要如何访问这个资源(http://)。

   端口 与  URL标准格式

何为端口?端口(Port),相当于一种数据的传输通道。用于接受某些数据,然后传输给相应的服务,而电脑将这些数据处理后,再将相应的回复通过开启的端口传给对方。

端口的作用:因为 IP 地址与网络服务的关系是一对多的关系。所以实际上因特网上是通过 IP 地址加上端口号来区分不同的服务的。

端口是通过端口号来标记的,端口号只有整数,范围是从0 到65535。

URL 标准格式。

通常而言,我们所熟悉的 URL 的常见定义格式为:

scheme://host[:port#]/path/.../[;url-params][?query-string][#anchor]

scheme //有我们很熟悉的http、https、ftp以及著名的ed2k,迅雷的thunder等。
host   //HTTP服务器的IP地址或者域名
port#  //HTTP服务器的默认端口是80,这种情况下端口号可以省略。如果使用了别的端口,必须指明,例如tomcat的默认端口是8080 http://www.cnblogs.com:8080/
path   //访问资源的路径
url-params  //所带参数
query-string    //发送给http服务器的数据
anchor //锚点定位

 

利用 <a> 标签自动解析 url

开发当中一个很常见的场景是,需要从 URL 中提取一些需要的元素,譬如 host 、 请求参数等等。

通常的做法是写正则去匹配相应的字段,当然,这里要安利下述这种方法,来自 James 的 blog,原理是动态创建一个 a 标签,利用浏览器的一些原生方法及一些正则(为了健壮性正则还是要的),完美解析 URL ,获取我们想要的任意一个部分。

代码如下:

// This function creates a new anchor element and uses location
// properties (inherent) to get the desired URL data. Some String
// operations are used (to normalize results across browsers).

function parseURL(url) {
    var a =  document.createElement(‘a‘);
    a.href = url;
    return {
        source: url,
        protocol: a.protocol.replace(‘:‘,‘‘),
        host: a.hostname,
        port: a.port,
        query: a.search,
        params: (function(){
            var ret = {},
                seg = a.search.replace(/^?/,‘‘).split(‘&‘),
                len = seg.length, i = 0, s;
            for (;i<len;i++) {
                if (!seg[i]) { continue; }
                s = seg[i].split(‘=‘);
                ret[s[0]] = s[1];
            }
            return ret;
        })(),
        file: (a.pathname.match(//([^/?#]+)$/i) || [,‘‘])[1],
        hash: a.hash.replace(‘#‘,‘‘),
        path: a.pathname.replace(/^([^/])/,‘/$1‘),
        relative: (a.href.match(/tps?://[^/]+(.+)/) || [,‘‘])[1],
        segments: a.pathname.replace(/^//,‘‘).split(‘/‘)
    };
}

Usage 使用方法:

var myURL = parseURL(‘http://abc.com:8080/dir/index.html?id=255&m=hello#top‘);

myURL.file;     // = ‘index.html‘
myURL.hash;     // = ‘top‘
myURL.host;     // = ‘abc.com‘
myURL.query;    // = ‘?id=255&m=hello‘
myURL.params;   // = Object = { id: 255, m: hello }
myURL.path;     // = ‘/dir/index.html‘
myURL.segments; // = Array = [‘dir‘, ‘index.html‘]
myURL.port;     // = ‘8080‘
myURL.protocol; // = ‘http‘
myURL.source;   // = ‘http://abc.com:8080/dir/index.html?id=255&m=hello#top‘

利用上述方法,即可解析得到 URL 的任意部分。

  URL 编码

为什么要进行URL编码?通常如果一样东西需要编码,说明这样东西并不适合直接进行传输。

1、会引起歧义:例如 URL 参数字符串中使用 key=value 这样的键值对形式来传参,键值对之间以 & 符号分隔,如 ?postid=5038412&t=1450591802326,服务器会根据参数串的 & 和 = 对参数进行解析,如果 value 字符串中包含了 = 或者 & ,那么势必会造成接收 URL 的服务器解析错误,因此必须将引起歧义的 & 和 = 符号进行转义, 也就是对其进行编码。

2、非法字符:又如,URL 的编码格式采用的是 ASCII 码,而不是 Unicode,这也就是说你不能在 URL 中包含任何非 ASCII 字符,例如中文。否则如果客户端浏览器和服务端浏览器支持的字符集不同的情况下,中文可能会造成问题。

那么如何编码?如下:

  escape 、 encodeURI 、encodeURIComponent 

  escape()

首先想声明的是,W3C把这个函数废弃了,身为一名前端如果还用这个函数是要打脸的

escape只是对字符串进行编码(而其余两种是对URL进行编码),与URL编码无关。编码之后的效果是以 %XX 或者 %uXXXX 这种形式呈现的。它不会对 ASCII字符、数字 以及 @ * / + 进行编码。

根据 MDN 的说明,escape 应当换用为 encodeURI 或 encodeURIComponent;unescape 应当换用为 decodeURI 或 decodeURIComponent。escape 应该避免使用。举例如下:

encodeURI(‘https://www.baidu.com/ a b c‘)
// "https://www.baidu.com/%20a%20b%20c"
encodeURIComponent(‘https://www.baidu.com/ a b c‘)
// "https%3A%2F%2Fwww.baidu.com%2F%20a%20b%20c"

//而 escape 会编码成下面这样,eocode 了冒号却没 encode 斜杠,十分怪异,故废弃之
escape(‘https://www.baidu.com/ a b c‘)
// "https%3A//www.baidu.com/%20a%20b%20c" 

  encodeURI()

encodeURI() 是 Javascript 中真正用来对 URL 编码的函数。它着眼于对整个URL进行编码。

encodeURI("http://www.cnblogs.com/season-huang/some other thing");
//"http://www.cnblogs.com/season-huang/some%20other%20thing";

编码后变为上述结果,可以看到空格被编码成了%20,而斜杠 /冒号 : 并没有被编码。

是的,它用于对整个 URL 直接编码,不会对 ASCII字母 、数字 、 ~ ! @ # $ & * ( ) = : / , ; ? + ‘ 进行编码。

encodeURI("[email protected]#$&*()=:/,;?+‘")
// [email protected]#$&*()=:/,;?+‘

  encodeURIComponent()

嘿,有的时候,我们的 URL 长这样子,请求参数中带了另一个 URL :

var URL = "http://www.a.com?foo=http://www.b.com?t=123&s=456";

直接对它进行 encodeURI 显然是不行的。因为 encodeURI 不会对冒号 : 及斜杠 / 进行转义,那么就会出现上述所说的服务器接受到之后解析会有歧义。

encodeURI(URL)
// "http://www.a.com?foo=http://www.b.com?t=123&b=456"

这个时候,就该用到 encodeURIComponent() 。它的作用是对 URL 中的参数进行编码,记住是对参数,而不是对整个 URL 进行编码。

因为它仅仅不对 ASCII字母、数字 ~ ! * ( ) ‘  进行编码。

错误的用法:

var URL = "http://www.a.com?foo=http://www.b.com?t=123&s=456";
encodeURIComponent(URL);
// "http%3A%2F%2Fwww.a.com%3Ffoo%3Dhttp%3A%2F%2Fwww.b.com%3Ft%3D123%26s%3D456"
// 错误的用法,看到第一个 http 的冒号及斜杠也被 encode 了 

正确的用法:encodeURIComponent() 着眼于对单个的参数进行编码:

var param = "http://www.b.com?t=123&s=456"; // 要被编码的参数
URL = "http://www.a.com?foo="+encodeURIComponent(param);
//"http://www.a.com?foo=http%3A%2F%2Fwww.b.com%3Ft%3D123%26s%3D456"

利用上述的使用<a>标签解析 URL 以及根据业务场景配合 encodeURI() 与 encodeURIComponent() 便能够很好的处理 URL 的编码问题。

应用场景最常见的一个是手工拼接 URL 的时候,对每对 key-value 用 encodeURIComponent 进行转义,再进行传输。

原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

时间: 2024-12-21 18:50:52

【基础进阶】URL详解与URL编码的相关文章

URL详解与URL编码

作为前端,每日与 URL 打交道是必不可少的.但是也许每天只是单纯的用,对其只是一知半解,随着工作的展开,我发现在日常抓包调试,接口调用,浏览器兼容等许多方面,不深入去理解URL与URL编码则会踩到很多坑.故写下此篇文章,详解一下 URL . URL 与 URI 很多人会混淆这两个名词. URL:(Uniform/Universal Resource Locator 的缩写,统一资源定位符). URI:(Uniform Resource Identifier 的缩写,统一资源标识符). 关系:

Fiddler抓包6-get请求(url详解)

前言 上一篇介绍了Composer的功能,可以模拟get和post请求,get请求有些是不带参数的,这种比较容易,直接放到url地址栏就行.有些get请求会带有参数,本篇详细介绍url地址格式. 一.url详解 1.url就是我们平常打开百度在地址栏输入的:https:www.baidu.com,如下图,这个是最简单的url地址,打开的是百度的主页 2.再看一个稍微复杂一点的url,在百度输入框输入:上海悠悠博客园 3.查看url地址栏,对比之前的百度首页url地址,后面多了很多参数.当然最主要

三、get请求(url详解)

前言 上一篇介绍了Composer的功能,可以模拟get和post请求,get请求有些是不带参数的,这种比较容易,直接放到url地址栏就行.有些get请求会带有参数,本篇详细介绍url地址格式. 一.url详解 1.url就是我们平常打开百度在地址栏输入的:https:www.baidu.com,如下图,这个是最简单的url地址,打开的是百度的主页 2.再看一个稍微复杂一点的url,在百度输入框输入:上海悠悠博客园 3.查看url地址栏,对比之前的百度首页url地址,后面多了很多参数.当然最主要

06_Fiddler_get请求(url详解)

介绍了Composer的功能,可以模拟get和post请求,get请求有些是不带参数的,这种比较容易,直接放到url地址栏就行.有些get请求会带有参数,本篇详细介绍url地址格式. 一.url详解 1.url就是我们平常打开百度在地址栏输入的:https:www.baidu.com,如下图,这个是最简单的url地址,打开的是百度的主页 2.再看一个稍微复杂一点的url,在百度输入框输入:上海悠悠博客园 3.查看url地址栏,对比之前的百度首页url地址,后面多了很多参数.当然最主要的参数是:w

基础拾遗------webservice详解

基础拾遗 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗------接口详解 基础拾遗------泛型详解 前言 工作当中常用的服务接口有三个wcf,webservice和webapi.首先第一个接触的就是webservice,今天大致总结一下. 1.webservice概念相关 1.1.Web Service也叫XML Web Service WebService 是一种可以接收从Inter

Android进阶——Preference详解之Preference系的基本应用和管理(二)

引言 前面一篇文章Android进阶--Preference详解之初识Preference及Preference系(一)简单描述下了Preference的家族构成和基本知识,相信对于Preference早已不会陌生,肯定也跃跃欲试了吧,这篇文章就给大家总结下Preference.PreferenceActivity.PreferenceGroup.RingtonePreference的普通应用和管理,还有通过一些测试来验证一些机制和原理. 一.PreferenceActivity 1.Prefe

java笔记--反射机制之基础总结与详解

一.反射之实例化Class类的5种方式: java的数据类型可以分为两类,即引用类型和原始类型(即基本数据类型). 对于每种类型的对象,java虚拟机会实例化不可变的java.lang.Class对象. 它提供了在运行时检查对象属性的方法,这些属性包括它的成员和类型信息. 更重要的是Class对象是所有反射API的入口. Class类是泛型类,可以使用@SuppressWarnings("unchecked")忽略泛型或者使用Class<V>类型. 获得Class对象的5种

Linux 程序设计学习笔记----终端及串口编程基础之概念详解

转载请注明出处,谢谢! linux下的终端及串口的相关概念有: tty,控制台,虚拟终端,串口,console(控制台终端)详解 部分内容整理于网络. 终端/控制台 终端和控制台都不是个人电脑的概念,而是多人共用的小型中型大型计算机上的概念. 1.终端 一台主机,连很多终端,终端为主机提供了人机接口,每个人都通过终端使用主机的资源. 终端有字符哑终端和图形终端两种. 控制台是另一种人机接口, 不通过终端与主机相连, 而是通过显示卡-显示器和键盘接口分别与主机相连, 这是人控制主机的第一人机接口.

Android进阶——Preference详解之Preference系的基本应用(三)

引言 前面一篇文章Android进阶--Preference详解之Preference系的基本应用和管理(二)介绍了二级Preference的使用和特点,接下来进入系统给我提供的底级Preference的使用CheckBox选择项CheckBoxPreference.EditText编辑对话框EditTextPreference.列表选择ListPreference.多项选择MultiSelectListPreference. 开关选择SwitchPreference的应用和管理.以期大家能在学