文章目录
- 一、URI的编码与解码
- 1.1 URI介绍
- 1.2 什么是encodeURI
- 1.3 什么是encodeURIComponent
- 1.4 应用场景
- 1.5 URI解码
- 1.6 扩展:内置对象URL
 
- 二、字符串的Base64编码与解码
- 2.1 ASCII字符编解码
- 2.2 非ASCII字符编解码
 
 
一、URI的编码与解码
1.1 URI介绍
URI指的是统一资源标识符(Uniform Resource Locator),它是用来标识和定位互联网上的资源(如网页、图片、文档等)的一种标识方式,它是一个广义的概念,如我们常用的URL就属于URI,URL能够定位给到互联网上的某个资源的位置。它主要有两个子集:
-  URL:用于标识和定位互联网上的资源的位置。它包括了资源的地址和访问方式,以确保资源能正常被定位和检索。通常由以下6部分组成。- 协议protocol:指定了资源的访问方式,常见的协议包括HTTP、HTTPS、FTP、mailto、file等。
- 域名(也叫主机名)Host:指定了资源所在的服务器或计算机的域名或IP地址。
- 端口Post:端口是可选的,它指定了服务器上用于处理请求的端口号。如果未指定端口,通常会使用默认端口,如 HTTP 的默认端口是 80。
- 路径Path:指定了服务器上资源的位置,通常是一个文件路径或目录路径。路径以斜杠/开头,如/images/pic.jpg。
- 查询参数Query:查询参数允许传递额外的信息给服务器,通常以?开头,参数之间用&分隔,如?name=John&age=30。
- 片段标识符(在location对象中是hash)Fragment:用于指定资源中的特定位置,如文档内的锚点。
 示例 URL:https://www.example.com:8080/images/pic.jpg?name=John&age=30#section2
- 协议
-  URN:用于标识资源的名称,而不关心资源的位置或如何访问它。URN 的目的是提供一个唯一的、永久的资源标识符。例如,ISBN(国际标准书号)就是一种 URN,它用于唯一标识图书,而不考虑图书的存储位置或如何获取它。
1.2 什么是encodeURI
encodeURI()是JavaScript的一个内置函数,用于将字符串中的特殊字符进行编码,以便能够在URL中传递。
其中encodeURI不会编码的特殊字符包括:【主要就是url常见字符】
| 类型 | 包含 | 
|---|---|
| 非转义字符 | A-Z、a-z、0-9、 _、.、-、!、~、'、(、) | 
| 保留字符 | :、/、?、=、&(前面这些属于url常见字符)、;、,、@、+、$ | 
| 数字符号 | #(这个也属于url常见字符) | 
语法:encodeURI(URI):URI是一个字符串,返回一个新字符串。
1.3 什么是encodeURIComponent
encodeURIComponent()也是JavaScript的一个内置函数,同样用于将字符串中的特殊字符进行编码,以便能够在URL中传递。与encodeURI()相比它会编码更多的字符。
它不会编码的特殊字符只有:
| 类型 | 包含 | 
|---|---|
| 非转义字符 | A-Z、a-z、0-9、 _、.、-、!、~、'、(、) | 
也就是说encodeURIComponent()会对url常见字符进行编码。
语法:encodeURIComponent(uriComponent):uriComponent是一个string、number、boolean、null,undefined 或者任何 object。在编码之前,uriComponent 参数会被转化为字符串。返回新字符串。
下面我们通过代码对比encodeURI:
let url = "https://www.aaa.com/path?name=zhangsan&age=18#fragment1";
// 输出:https://www.aaa.com/path?name=zhangsan&age=18#fragment1
console.log(encodeURI(url));
// 输出:https%3A%2F%2Fwww.aaa.com%2Fpath%3Fname%3Dzhangsan%26age%3D18%23fragment1
console.log(encodeURIComponent(url));
可以明显看到encodeURIComponent对url常见字符进行了编码。
1.4 应用场景
1 输入内容编码
假设我们有一个搜索功能,用户可以输入关键字进行搜索。用户输入的关键字可能包含特殊字符,如空格、问号、和号等。为了将关键字作为 URL 参数传递给服务器,我们需要使用 encodeURIComponent 对其进行编码。
const userInput = "JavaScript 2a+ 学习?";// 编码用户输入
const encodedKeyword = encodeURIComponent(userInput);// 构建 URL
const searchURL = `https://example.com/search?keyword=${encodedKeyword}`;console.log(searchURL);  // https://example.com/search?keyword=JavaScript%202a%2B%20%E5%AD%A6%E4%B9%A0%3F
2 Ajax请求
在使用 JavaScript 进行 AJAX 请求时,encodeURIComponent 也非常有用。当使用 fetch 或 XMLHttpRequest 发送数据时,特别是发送 POST 请求时,需要确保请求体中的数据是经过编码的。
let data = {username: "John Doe",email: "john.doe@example.com",
};// 将 JavaScript 对象转换为 URL 编码的字符串
const encodedData = Object.keys(data).map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`).join("&");console.log(encodedData);  // username=John%20Doe&email=john.doe%40example.comfetch("https://example.com/submit", {method: "POST",headers: {"Content-Type": "application/x-www-form-urlencoded",},body: encodedData,
});
1.5 URI解码
使用decodeURI和decodeURIComponent可以解码
// 未编码的str: username=John Doe&email=john.doe@example.com
// 输出:username=John Doe&email=john.doe%40example.com
console.log(decodeURI('username=John%20Doe&email=john.doe%40example.com'));
// 输出:username=John Doe&email=john.doe@example.com
console.log(decodeURIComponent('username=John%20Doe&email=john.doe%40example.com'));
可以看到由于encodeURI不能编码保留字符@,因此decodeURI也不能将@对应的编码%40转回@。
1.6 扩展:内置对象URL
这里扩展一下内置对象URL。
我们可以使用 new URL() 构造函数创建 URL 对象并访问其属性方法,类似于location,URL 对象还提供了一些方法,例如searchParams 属性可以访问查询字符串参数等。
const url = new URL("https://www.aaa.com/path?name=zhangsan&age=18#fragment1");
console.log(url.protocol); // https:  协议
console.log(url.host); // www.aaa.com  域名
console.log(url.port); //   端口
console.log(url.pathname); // /path  路径
console.log(url.search); // ?name=zhangsan&age=18  query
console.log(url.hash); // #fragment1  hash
console.log(url.origin); // https://www.aaa.com  origin// 获取参数
console.log(url.searchParams.get("name"));  // zhangsan// 下面这种形式也能获取参数
const params = new URLSearchParams(url.search)
console.log(params.get('name'))  // zhangsan
二、字符串的Base64编码与解码
由于 Base64 编码后的字符串只包含 ASCII 字符,因此可以安全地传输或存储到不支持二进制数据的地方(如URL、XML等),以避免出现数据传输或存储时的格式问题。
toa() 和 atob() 是 JavaScript 内置的用于 Base64 编码和解码的方法。
2.1 ASCII字符编解码
btoa() 方法用于将字符串转换为 Base64 编码。它接受一个字符串作为参数,返回一个 Base64 编码的字符串。例如:
ASCII字符编码为Base64
const str = 'Hello world'
const encodedStr = btoa(str)console.log(encodedStr) // SGVsbG8gd29ybGQ=
atob()方法用于将Base64的字符串转换为原始字符串,如下:
解码
const encodedStr = 'SGVsbG8gd29ybGQ='
const str = atob(encodedStr)
console.log(str) // Hello world
2.2 非ASCII字符编解码
需要注意的是,btoa() 和 atob() 方法只能处理 ASCII 字符串(包含 128 个字符,其中包括英文字母、数字、标点符号和一些控制字符),如果字符串中包含非 ASCII 字符(如中文文字),需要先将其转换为UTF-8编码的字节数组,再进行 Base64 编码。例如:
非ASCII字符编码Base64
const str = "你好 世界";
// TextEncoder构造函数接受码位流作为输入,并提供 UTF-8 字节流作为输出
const utf8Bytes = new TextEncoder().encode(str);  // 转成utf8编码的字节数组
const encodedStr = btoa(String.fromCharCode(...utf8Bytes));  // 编码为base64编码的ASCII字符串
console.log(encodedStr); // 5L2g5aW9IOS4lueVjA==
解码
const decodedBytes = atob('5L2g5aW9IOS4lueVjA==').split('').map(char => char.charCodeAt(0))  // 转成utf8编码的字节数组
// TextDecoder接受一个ArrayBuffer、TypedArray或包含要解码的编码文本的对象,返回解码后的字符串。
const decodedStr = new TextDecoder().decode(new Uint8Array(decodedBytes))  //
console.log(decodedStr) // 你好 世界
应用场景:
在前端开发中,经常需要将图片或音频等二进制数据转换为 Base64 编码的字符串,以便在网页中直接显示或传输。
下面代码实现了将图片资源转成base64格式。
async function mediaToBase64(filePath) {// 将图片资源转成blob格式const blob = await fetch(filePath).then((res) => res.blob());// 创建一个Promise对象,将Base64编码后的图片数据存储在变量base64中const base64 = await new Promise((resolve) => {// 创建一个FileReader对象,用于将Blob对象中的数据转换为Base64编码的字符串const reader = new FileReader();// 当FileReader对象读取完成时触发onload事件reader.onload = () => {console.log(reader.result);  // data:image/png;base64,base64字符串....// 将DataURL中的Base64编码字符串取出,并将其存储在变量base64中resolve(reader.result.split(",")[1]);};// 将Blob对象中的数据读取为DataURLreader.readAsDataURL(blob);});return base64;  // 返回的是一个promise对象 所以接受结果的时候需要.then拿到res
}
mediaToBase64("./img.png").then((res) => {console.log(res);  // base64字符串....
});
要注意的是,由于 Base64 编码后的字符串通常比原始二进制数据大约33%,因此Base64格式只适合传输小量数据。
参考博客:
- 掌握 Web API 中常用的编码和解码技术:encodeURI、encodeURIComponent、new URL、btoa() 和 atob()
- 一个由于前端缺少 encodeURIComponent 引起的登录问题的分析和解决
- (JavaScript)escape、encodeURI、encodeURIComponent的介绍与区别